Corretta struttura degli asset SCSS in Rails


86

Quindi, ho una app/assets/stylesheets/struttura di directory simile a questa:

   |-dialogs
   |-mixins
   |---buttons
   |---gradients
   |---vendor_support
   |---widgets
   |-pages
   |-structure
   |-ui_elements

In ogni directory, ci sono più parziali sass (di solito * .css.scss, ma uno o due * .css.scss.erb).

Potrei supporre molto, ma rails DOVREBBE compilare automaticamente tutti i file in quelle directory a causa di *= require_tree .application.css, giusto?

Recentemente ho provato a ristrutturare questi file rimuovendo tutte le variabili di colore e inserendole in un file nella app/assets/stylesheetscartella principale (_colors.css.scss). Ho quindi creato un file nella app/assets/stylesheetscartella principale chiamato master.css.scss che assomiglia a questo:

// Color Palette 
@import "colors";

// Mixins
@import "mixins/buttons/standard_button";
@import "mixins/gradients/table_header_fade";
@import "mixins/vendor_support/rounded_corners";
@import "mixins/vendor_support/rounded_corners_top";
@import "mixins/vendor_support/box_shadow";
@import "mixins/vendor_support/opacity";

Non capisco davvero come rails gestisca l'ordine di compilazione delle risorse, ma ovviamente non è a mio favore. Sembra che nessuno dei file si renda conto di avere variabili o mixin importati, quindi genera errori e non riesco a compilare.

Undefined variable: "$dialog_divider_color".
  (in /home/blah/app/assets/stylesheets/dialogs/dialog.css.scss.erb)

Undefined mixin 'rounded_corners'.
  (in /home/blah/app/assets/stylesheets/widgets.css.scss)

La variabile $dialog_divider_colorè chiaramente definita in _colors.css.scss e _master.css.scssimporta i colori e tutti i miei mixin. Ma a quanto pare Rails non ha ricevuto quel promemoria.

C'è un modo per correggere questi errori o dovrò ricorrere a rimettere tutte le mie definizioni di variabili in ogni singolo file, così come tutte le importazioni di mixin?

Sfortunatamente, questo ragazzo non sembra pensare che sia possibile, ma spero che si sbagli. Tutti i pensieri sono molto apprezzati.

Risposte:


126

Il problema con i CSS è che non vuoi aggiungere automaticamente tutti i file. L'ordine in cui i tuoi fogli vengono caricati ed elaborati dal browser è essenziale. Quindi finirai sempre per importare esplicitamente tutti i tuoi css.

Ad esempio, supponiamo di avere un foglio normalize.css , per ottenere un aspetto predefinito invece di tutte le orribili diverse implementazioni del browser. Questo dovrebbe essere il primo file caricato dal browser. Se includi casualmente questo foglio da qualche parte nelle tue importazioni CSS, non solo sovrascriverà gli stili predefiniti del browser, ma anche tutti gli stili definiti in tutti i file CSS che sono stati caricati prima di esso. Questo vale per le variabili e i mixin.

Dopo aver visto una presentazione di Roy Tomeij a Euruko2012, ho deciso il seguente approccio se hai molti CSS da gestire.

In genere utilizzo questo approccio:

  1. Rinomina tutti i file .css esistenti in .scss
  2. Rimuovi tutto il contenuto da application.scss

Inizia ad aggiungere le direttive @import a application.scss.

Se stai usando twitters bootstrap e alcuni fogli css di tua scelta, devi prima importare bootstrap, perché ha un foglio per reimpostare gli stili. Quindi aggiungi @import "bootstrap/bootstrap.scss";al tuo application.scss.

Il file bootstrap.scss ha il seguente aspetto:

// CSS Reset
@import "reset.scss";

// Core
@import "variables.scss";
@import "mixins.scss";

// Grid system and page structure
@import "scaffolding.scss";

// Styled patterns and elements
@import "type.scss";
@import "forms.scss";
@import "tables.scss";
@import "patterns.scss";

E il tuo application.scssfile assomiglia a:

@import "bootstrap/bootstrap.scss";

A causa dell'ordine delle importazioni, è ora possibile utilizzare le variabili, caricate @import "variables.scss";in qualsiasi altro .scssfile importato dopo di esse. Quindi possono essere utilizzati nella type.scsscartella bootstrap ma anche in my_model.css.scss.

Dopo questo crea una cartella denominata partialso modules. Questo sarà il luogo della maggior parte degli altri file. Puoi semplicemente aggiungere l'importazione al application.scssfile in modo che assomigli a:

@import "bootstrap/bootstrap.scss";
@import "partials/*";

Ora se crei un po 'di CSS per modellare un articolo sulla tua home page. Basta creare partials/_article.scsse verrà aggiunto al file compilato application.css. A causa dell'ordine di importazione puoi anche utilizzare qualsiasi mixin e variabile di bootstrap nei tuoi file scss.

L'unico inconveniente di questo metodo che ho trovato finora è che a volte devi forzare una ricompilazione dei file / *. Scss parziali perché rails non lo farà sempre per te.


4
Grazie, questo è l'approccio con cui ho finito per seguire. Odio questa soluzione perché devi aggiungere manualmente ogni file che includi ogni volta che ne crei uno, ma sembra che quando sono coinvolti CSS, l'ordine contenga. Normalmente direi che è solo una cattiva scrittura CSS, ma se stai usando cose fornite dal fornitore (cioè bootstrap come hai detto sopra), tendi a sovrascrivere le cose, quindi sono d'accordo a malincuore che questo è l'approccio giusto.
David Savage

1
Grazie! Un approccio molto carino e una buona spiegazione! Un progetto degno di nota: questo plugin FireBug , FireSass , mostra il numero di riga di my_model.css.sass invece della riga dell'applicazione compilata.css
BBQ Chef

Con questo approccio, se voglio cambiare il colore del mio collegamento predefinito in rosso che si applica a tutti i miei parziali, come lo fareste? Dove lo metteresti?
chh

1
Si noti che questo approccio è consigliato anche in The Asset Pipeline Rails Guide . Cerca "Se vuoi usare più file Sass".
ybakos

1
@ Lykos sì, rimuovi tutto da application.csse rinominalo in application.scss. Perché require_treeinclude solo tutto e di solito vuoi controllare l'ordine
Benjamin Udink ten Cate

8

per utilizzare variabili e simili tra i file, è necessario utilizzare la direttiva @import. i file vengono importati nell'ordine specificato.

quindi, utilizzare application.css per richiedere il file che dichiara le importazioni. questo è il modo per ottenere il controllo che desideri.

infine, nel tuo file layout.erb, puoi specificare quale file css "master" usare

l'esempio sarà più utile:

diciamo che hai due moduli nella tua app che richiedono diversi set di css: "application" e "admin"

i file

|-app/
|-- assets/
|--- stylesheets/
|     // the "master" files that will be called by the layout
|---- application.css
|---- application_admin.css
|
|     // the files that contain styles
|---- config.scss
|---- styles.scss
|---- admin_styles.scss
|
|     // the files that define the imports
|---- app_imports.scss
|---- admin_imports.scss
|
|
|-- views/
|--- layouts/
|---- admin.html.haml
|---- application.html.haml

ecco come appaiono i file all'interno:

-------- THE STYLES

-- config.scss
// declare variables and mixins
$font-size: 20px;

--  app_imports.scss
// using imports lets you use variables from `config` in `styles`
@import 'config'
@import 'styles'

-- admin_imports.scss
// for admin module, we import an additional stylesheet
@import 'config'
@import 'styles'
@import 'admin_styles'

-- application.css
// in the master application file, we require the imports
*= require app_imports
*= require some_other_stylesheet_like_a_plugin
*= require_self

-- application_admin.css
// in the master admin file, we require the admin imports
*= require admin_imports
*= require some_other_stylesheet_like_a_plugin
*= require_self


-------- THE LAYOUTS

-- application.html.haml
// in the application layout, we call the master css file
= stylesheet_link_tag "application", media: "all"

--  admin.html.haml
// in the admin layout, we call the admin master css file
= stylesheet_link_tag "application_admin", media: "all"

7

Crea la seguente struttura di cartelle:

+ assets
|
--+ base
| |
| --+ mixins (with subfolders as noted in your question)
|
--+ styles
  |
  --+ ...

Nella cartella basecreare un file "globals.css.scss". In questo file, dichiara tutte le tue importazioni:

@import 'base/colors';
@import 'base/mixins/...';
@import 'base/mixins/...';

In you application.css.scss, dovresti quindi avere:

*= require_self
*= depends_on ./base/globals.css.scss
*= require_tree ./styles

E come ultimo passaggio (questo è importante), dichiara @import 'base/globals'in ogni file di stile dove vuoi usare variabili o mixin. Potresti considerare questo sovraccarico, ma in realtà mi piace l'idea che devi dichiarare le dipendenze dei tuoi stili in ogni file. Naturalmente, è importante importare solo mixin e variabili in globals.css.scss poiché non aggiungono definizioni di stile. Altrimenti le definizioni di stile verrebbero incluse più volte nel tuo file precompilato ...


L'ho provato ma non sono mai riuscito a farlo funzionare correttamente (continuavo a ricevere errori di variabili mancanti). Forse non ho fatto qualcosa correttamente, ma penso che alla fine l'approccio di elencare manualmente ogni file sia la strada giusta da percorrere, poiché con l'ordine CSS è importante.
David Savage

Puoi ancora usare questo approccio: invece di "require_tree ..." aggiungi semplicemente una riga per ogni singolo file. Questo farà sì che SASS importi i file nell'ordine corretto. Per quanto riguarda la soluzione che si sta utilizzando, si prega di dare un'occhiata a questo post che ho appena trovato: stackoverflow.com/questions/7046495/... Assicurati di includere il directivie depends_on nel file application.css.
emrass

4

Secondo questa domanda , puoi usare SOLOapplication.css.sass per definire l'importazione e condividere le variabili tra i tuoi modelli.

=> Sembra essere solo una questione di nome.

Un altro modo può essere includere tutto e disabilitare questa pipeline .


Questa è essenzialmente la stessa cosa che Benjamin Udink ten Cate ha offerto nella seconda parte della tua risposta, ma assegnargli la taglia poiché la sua soluzione è più esplicativa.
David Savage

1

Ho avuto un problema molto simile. Ciò che mi ha aiutato è stato inserire il carattere di sottolineatura nell'istruzione @import durante l'importazione del partial. Così

@import "_base";

invece di

@import "base";

Potrebbe essere uno strano bug ...

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.