Structure d'actifs SCSS appropriée dans les rails

86

Donc, j'ai une app/assets/stylesheets/structure de répertoires qui ressemble à ceci:

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

Dans chaque répertoire, il y a plusieurs partiels sass (généralement * .css.scss, mais un ou deux * .css.scss.erb).

Je suppose peut-être beaucoup, mais les rails DEVRAIENT compiler automatiquement tous les fichiers de ces répertoires à cause de *= require_tree .dans application.css, non?

J'ai récemment essayé de restructurer ces fichiers en supprimant toutes les variables de couleur et en les plaçant dans un fichier dans le app/assets/stylesheetsdossier racine (_colors.css.scss). J'ai ensuite créé un fichier dans le app/assets/stylesheetsdossier racine appelé master.css.scss qui ressemble à ceci:

// 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";

Je ne comprends pas vraiment comment les rails gèrent l'ordre de compilation des actifs, mais ce n'est évidemment pas en ma faveur. Il semble qu'aucun des fichiers ne réalise qu'ils ont des variables ou des mixins importés, et donc cela génère des erreurs et je ne peux pas compiler.

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 variable $dialog_divider_colorest clairement définie dans _colors.css.scss, et _master.css.scssimporte les couleurs et tous mes mixins. Mais apparemment, les rails n'ont pas reçu ce mémo.

Existe-t-il un moyen de corriger ces erreurs, ou dois-je recourir à replacer toutes mes définitions de variables dans chaque fichier individuel, ainsi que toutes les importations de mixin?

Malheureusement, ce type ne semble pas penser que c'est possible, mais j'espère qu'il a tort. Toutes les pensées sont grandement appréciées.

David Savage
la source

Réponses:

126

Le problème avec CSS est que vous ne voulez pas ajouter automatiquement tous les fichiers. L'ordre dans lequel vos feuilles sont chargées et traitées par le navigateur est primordial. Ainsi, vous finirez toujours par importer explicitement tous vos css.

Par exemple, disons que vous avez une feuille normalize.css , pour obtenir un look par défaut au lieu de toutes les horribles implémentations de navigateur différentes. Ce devrait être le premier fichier que le navigateur charge. Si vous incluez simplement au hasard cette feuille quelque part dans vos importations css, cela remplacera non seulement les styles par défaut du navigateur, mais également tous les styles définis dans tous les fichiers css qui ont été chargés avant lui. Il en va de même pour les variables et les mixins.

Après avoir vu une présentation de Roy Tomeij à Euruko2012, j'ai opté pour l'approche suivante si vous avez beaucoup de CSS à gérer.

J'utilise généralement cette approche:

  1. Renommez tous les fichiers .css existants en .scss
  2. Supprimer tout le contenu de application.scss

Commencez à ajouter des directives @import à application.scss.

Si vous utilisez le bootstrap de twitters et quelques feuilles CSS de votre choix, vous devez d'abord importer le bootstrap, car il a une feuille pour réinitialiser les styles. Donc, vous ajoutez @import "bootstrap/bootstrap.scss";à votre application.scss.

Le fichier bootstrap.scss ressemble à:

// 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";

Et votre application.scssfichier ressemble à:

@import "bootstrap/bootstrap.scss";

En raison de l'ordre des importations, vous pouvez désormais utiliser les variables, chargées @import "variables.scss";dans tout autre .scssfichier importé après lui. Ils peuvent donc être utilisés dans type.scssle dossier bootstrap mais aussi dans my_model.css.scss.

Après cela, créez un dossier nommé partialsou modules. Ce sera l'emplacement de la plupart des autres fichiers. Vous pouvez simplement ajouter l'importation au application.scssfichier pour qu'elle ressemble à:

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

Maintenant, si vous faites un peu de CSS pour styliser un article sur votre page d'accueil. Créez simplementpartials/_article.scss et il sera ajouté au fichier compilé application.css. En raison de l'ordre d'importation, vous pouvez également utiliser des mixins et des variables d'amorçage dans vos propres fichiers scss.

Le seul inconvénient de cette méthode que j'ai trouvé jusqu'à présent est que vous devez parfois forcer une recompilation des fichiers partiels / *. Scss car les rails ne le feront pas toujours pour vous.

Benjamin Udink ten Cate
la source
4
Merci, c'est l'approche que j'ai suivie. Je déteste cette solution car vous devez ajouter manuellement chaque fichier que vous incluez chaque fois que vous en créez un, mais il semble que lorsque CSS est impliqué, l'ordre compte. Normalement, je dirais que c'est juste une mauvaise écriture CSS, mais si vous utilisez des éléments fournis par le fournisseur (c'est-à-dire bootstrap comme vous le mentionnez ci-dessus), vous avez tendance à vouloir écraser les choses, donc je suis d'accord à contrecœur que c'est la bonne approche.
David Savage
1
Merci! Une très belle approche et une bonne explication! Un projet à mentionner: ce plugin FireBug, FireSass , affiche le numéro de ligne de my_model.css.sass au lieu de la ligne de l'application compilée.css
BBQ Chef
Avec cette approche, si je veux changer ma couleur de lien par défaut en rouge qui s'applique à tous mes partiels, comment feriez-vous cela? Où le mettriez-vous?
chh
1
Notez que cette approche est également recommandée dans The Asset Pipeline Rails Guide . Recherchez «Si vous souhaitez utiliser plusieurs fichiers Sass».
ybakos
1
@Lykos oui, vous supprimez tout de application.csset renommez-le en application.scss. Parce que require_treecomprend tout et vous voulez généralement contrôler l'ordre
Benjamin Udink ten Cate
8

pour utiliser des variables et autres dans les fichiers, vous devez utiliser la directive @import. les fichiers sont importés dans l'ordre spécifié.

puis, utilisez application.css pour exiger le fichier qui déclare les importations. c'est ainsi que vous obtiendrez le contrôle souhaité.

enfin, dans votre fichier layout.erb, vous pouvez spécifier quel fichier css "maître" utiliser

l'exemple sera plus utile:

disons que vous avez deux modules dans votre application qui nécessitent différents ensembles de css: "application" et "admin"

les fichiers

|-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

voici à quoi ressemblent les fichiers à l'intérieur:

-------- 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"
Doug Lee
la source
7

Créez la structure de dossiers suivante:

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

Dans le dossier, basecréez un fichier "globals.css.scss". Dans ce fichier, déclarez toutes vos importations:

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

Dans votre application.css.scss, vous devriez alors avoir:

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

Et comme dernière étape (c'est important), déclarez @import 'base/globals'dans chaque fichier de style où vous souhaitez utiliser des variables ou des mixins. Vous pourriez envisager cette surcharge, mais j'aime en fait l'idée que vous devez déclarer les dépendances de vos styles dans chaque fichier. Bien sûr, il est important que vous importiez uniquement des mixins et des variables dans le fichier globals.css.scss car ils n'ajoutent pas de définitions de style. Sinon, les définitions de style seraient incluses plusieurs fois dans votre fichier précompilé ...

emrass
la source
J'ai essayé cela mais je n'ai jamais pu le faire fonctionner correctement (je recevais toujours des erreurs de variable manquantes). Peut-être que je n'ai pas fait quelque chose correctement, mais je pense qu'en fin de compte, l'approche consistant à répertorier manuellement chaque fichier est la bonne voie à suivre, car l'ordre CSS compte.
David Savage
Vous pouvez toujours utiliser cette approche: au lieu de "require_tree ...", ajoutez simplement une ligne pour chaque fichier individuel. Cela permettra à SASS d'importer les fichiers dans le bon ordre. Concernant la solution que vous utilisez maintenant, veuillez jeter un œil à ce post que je viens de trouver: stackoverflow.com/questions/7046495/… Assurez-vous d'inclure le directivie depend_on dans votre fichier application.css.
emrass
4

Selon cette question , vous pouvez utiliser UNIQUEMENTapplication.css.sass pour définir des variables d'importation et de partage entre vos modèles.

=> Cela ne semble être qu'une question de nom.

Une autre façon peut être de tout inclure et de désactiver ce pipeline .

Coren
la source
C'est essentiellement la même chose que Benjamin Udink ten Cate a offert dans la deuxième partie de votre réponse, mais lui attribuer la prime comme sa solution est plus explicative.
David Savage
1

J'ai eu un problème très similaire. Ce qui m'a aidé, c'est de mettre le trait de soulignement dans l'instruction @import lors de l'importation du partiel. Donc

@import "_base";

au lieu de

@import "base";

Cela pourrait être un étrange bug ...

Bernát
la source