Richtige SCSS-Asset-Struktur in Rails

86

Ich habe also eine app/assets/stylesheets/Verzeichnisstruktur, die ungefähr so ​​aussieht:

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

In jedem Verzeichnis gibt es mehrere Sass-Partials (normalerweise * .css.scss, aber ein oder zwei * .css.scss.erb).

Ich gehe vielleicht von viel aus, aber Rails MÜSSEN aufgrund von *= require_tree .application.css automatisch alle Dateien in diesen Verzeichnissen kompilieren , oder?

Ich habe kürzlich versucht, diese Dateien neu zu strukturieren, indem ich alle Farbvariablen entfernt und in einer Datei im app/assets/stylesheetsStammordner (_colors.css.scss) abgelegt habe. Ich habe dann eine Datei im app/assets/stylesheetsStammordner namens master.css.scss erstellt, die folgendermaßen aussieht:

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

Ich verstehe nicht wirklich, wie Rails die Reihenfolge der Asset-Kompilierung handhabt, aber es ist offensichtlich nicht zu meinen Gunsten. Es scheint, dass keine der Dateien erkennt, dass Variablen oder Mixins importiert werden. Daher werden Fehler ausgegeben, und ich kann nicht kompilieren.

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)

Die Variable $dialog_divider_colorist in _colors.css.scss klar definiert und _master.css.scssimportiert Farben und alle meine Mixins. Aber anscheinend haben Rails dieses Memo nicht bekommen.

Gibt es eine Möglichkeit, diese Fehler zu beheben, oder muss ich alle meine Variablendefinitionen sowie alle Mixin-Importe wieder in jede einzelne Datei einfügen?

Leider scheint dieser Typ nicht zu glauben, dass es möglich ist, aber ich hoffe, er liegt falsch. Alle Gedanken werden sehr geschätzt.

David Savage
quelle

Antworten:

126

Das Problem mit CSS ist, dass Sie nicht automatisch alle Dateien hinzufügen möchten. Die Reihenfolge, in der Ihre Blätter vom Browser geladen und verarbeitet werden, ist wichtig. Sie werden also immer explizit alle Ihre CSS importieren.

Nehmen wir zum Beispiel an, Sie haben ein normalize.css- Blatt, um ein Standard-Erscheinungsbild anstelle aller schrecklich unterschiedlichen Browser-Implementierungen zu erhalten. Dies sollte die erste Datei sein, die der Browser lädt. Wenn Sie dieses Blatt nur zufällig irgendwo in Ihre CSS-Importe aufnehmen, überschreibt es nicht nur die Standardstile des Browsers, sondern auch alle Stile, die in allen zuvor geladenen CSS-Dateien definiert sind. Dies gilt auch für Variablen und Mixins.

Nachdem ich eine Präsentation von Roy Tomeij auf der Euruko2012 gesehen hatte, entschied ich mich für den folgenden Ansatz, wenn Sie viel CSS verwalten müssen.

Ich benutze im Allgemeinen diesen Ansatz:

  1. Benennen Sie alle vorhandenen CSS-Dateien in Scss um
  2. Entfernen Sie alle Inhalte aus application.scss

Fügen Sie @import-Anweisungen hinzu application.scss.

Wenn Sie Twitters Bootstrap und einige eigene CSS-Blätter verwenden, müssen Sie zuerst Bootstrap importieren, da es ein Blatt zum Zurücksetzen von Stilen enthält. Also fügst du @import "bootstrap/bootstrap.scss";zu deinem hinzu application.scss.

Die Datei bootstrap.scss sieht folgendermaßen aus:

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

Und Ihre application.scssDatei sieht aus wie:

@import "bootstrap/bootstrap.scss";

Aufgrund der Reihenfolge der Importe können Sie jetzt die Variablen verwenden, die @import "variables.scss";in jede andere danach .scssimportierte Datei geladen wurden . Sie können also sowohl im type.scssBootstrap-Ordner als auch in verwendet werden my_model.css.scss.

Danach erstellen Sie einen Ordner mit dem Namen partialsoder modules. Dies ist der Ort der meisten anderen Dateien. Sie können den Import einfach zur application.scssDatei hinzufügen, damit er wie folgt aussieht:

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

Nun, wenn Sie ein bisschen CSS machen, um einen Artikel auf Ihrer Homepage zu gestalten. Einfach erstellen partials/_article.scssund es wird dem kompilierten hinzugefügt application.css. Aufgrund der Importreihenfolge können Sie auch beliebige Bootstrap-Mixins und -Variablen in Ihren eigenen scss-Dateien verwenden.

Der einzige Nachteil dieser Methode, den ich bisher gefunden habe, ist, dass Sie manchmal eine Neukompilierung der partiellen / *. Scss-Dateien erzwingen müssen, da Rails dies nicht immer für Sie tun.

Benjamin Udink zehn Cate
quelle
4
Danke, das ist der Ansatz, den ich letztendlich gewählt habe. Ich hasse diese Lösung, weil Sie jede Datei, die Sie einschließen, jedes Mal manuell hinzufügen müssen, wenn Sie eine erstellen, aber es scheint, dass die Reihenfolge bei CSS eine Rolle spielt. Normalerweise würde ich sagen, dass dies nur schlechtes CSS-Schreiben ist, aber wenn Sie Dinge verwenden, die vom Hersteller bereitgestellt werden (dh Bootstrap, wie Sie oben erwähnt haben), möchten Sie die Dinge tendenziell überschreiben, daher stimme ich widerwillig zu, dass dies der richtige Ansatz ist.
David Savage
1
Vielen Dank! Ein sehr schöner Ansatz und eine gute Erklärung! Ein erwähnenswertes Projekt: Dieses FireBug-Plugin, FireSass , zeigt die Zeilennummer von my_model.css.sass anstelle der Zeile der kompilierten application.css
BBQ Chef
Wenn Sie bei diesem Ansatz meine Standard-Linkfarbe in Rot ändern möchten, die für alle meine Partials gilt, wie würden Sie das tun? Wo würdest du es hinstellen?
chh
1
Beachten Sie, dass dieser Ansatz auch im Asset Pipeline Rails-Handbuch empfohlen wird . Suchen Sie nach "Wenn Sie mehrere Sass-Dateien verwenden möchten".
Ybakos
1
@ Lykos ja du entfernst alles aus dem application.cssund benennst es um in application.scss. Weil es require_treeeinfach alles enthält und Sie normalerweise die Reihenfolge kontrollieren möchten
Benjamin Udink ten Cate
8

Um Variablen und dergleichen dateiübergreifend zu verwenden, müssen Sie die @ import-Direktive verwenden. Dateien werden in der angegebenen Reihenfolge importiert.

Verwenden Sie dann application.css, um die Datei anzufordern, die die Importe deklariert. Auf diese Weise erreichen Sie die gewünschte Kontrolle.

Schließlich können Sie in Ihrer Datei layout.erb angeben, welche CSS-Masterdatei verwendet werden soll

Beispiel wird hilfreicher sein:

Angenommen, Ihre App enthält zwei Module, die unterschiedliche CSS-Sätze benötigen: "application" und "admin".

die Dateien

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

So sehen die Dateien im Inneren aus:

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

Erstellen Sie die folgende Ordnerstruktur:

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

baseErstellen Sie im Ordner eine Datei "globals.css.scss". Deklarieren Sie in dieser Datei alle Ihre Importe:

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

In Ihrer application.css.scss sollten Sie dann haben:

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

Und als letzten Schritt (dies ist wichtig) deklarieren Sie @import 'base/globals'in jeder Stildatei, in der Sie Variablen oder Mixins verwenden möchten. Sie könnten diesen Aufwand in Betracht ziehen, aber ich mag die Idee, dass Sie die Abhängigkeiten Ihrer Stile in jeder Datei deklarieren müssen. Natürlich ist es wichtig, dass Sie nur Mixins und Variablen in die Datei globals.css.scss importieren, da diese keine Stildefinitionen hinzufügen. Andernfalls würden die Stildefinitionen mehrmals in Ihre vorkompilierte Datei aufgenommen ...

Emrass
quelle
Ich habe das ausprobiert, konnte es aber nie richtig zum Laufen bringen (es fehlten immer noch variable Fehler). Vielleicht habe ich etwas nicht richtig gemacht, aber ich denke am Ende ist der Ansatz, jede Datei manuell aufzulisten, der richtige Weg, da die CSS-Reihenfolge eine Rolle spielt.
David Savage
Sie können diesen Ansatz weiterhin verwenden: Anstelle von "require_tree ..." fügen Sie einfach eine Zeile für jede einzelne Datei hinzu. Dadurch importiert SASS die Dateien in der richtigen Reihenfolge. In Bezug auf die Lösung, die Sie jetzt verwenden, werfen Sie bitte einen Blick auf diesen Beitrag, den ich gerade gefunden habe: stackoverflow.com/questions/7046495/… Stellen Sie sicher, dass Sie die abhängige_on-Direktive in Ihre application.css-Datei aufnehmen.
Emrass
4

Entsprechend dieser Frage können Sie NUR verwenden application.css.sass, um Import- und Freigabevariablen zwischen Ihren Vorlagen zu definieren.

=> Es scheint nur eine Frage des Namens zu sein.

Eine andere Möglichkeit kann darin bestehen, alles einzuschließen und diese Pipeline zu deaktivieren .

Coren
quelle
Dies ist im Wesentlichen dasselbe, was Benjamin Udink ten Cate im zweiten Teil Ihrer Antwort angeboten hat, aber es ist erklärender, ihm das Kopfgeld als seine Lösung zu gewähren.
David Savage
1

Ich hatte ein sehr ähnliches Problem. Was mir geholfen hat, war, beim Importieren des Teils den Unterstrich in die @ import-Anweisung einzufügen. So

@import "_base";

anstatt

@import "base";

Es könnte ein seltsamer Fehler sein ...

Bernát
quelle