Struktur Aset SCSS yang Tepat di Rails

86

Jadi, saya memiliki app/assets/stylesheets/struktur direktori yang terlihat seperti ini:

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

Di setiap direktori, ada beberapa bagian sass (biasanya * .css.scss, tetapi satu atau dua * .css.scss.erb).

Saya mungkin berasumsi banyak, tetapi Rails HARUS secara otomatis mengkompilasi semua file di direktori tersebut karena *= require_tree .di application.css, bukan?

Saya baru-baru ini mencoba merestrukturisasi file-file ini dengan menghapus semua variabel warna dan menempatkannya dalam file di app/assets/stylesheetsfolder root (_colors.css.scss). Saya kemudian membuat file di app/assets/stylesheetsfolder root bernama master.css.scss yang terlihat seperti ini:

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

Saya tidak begitu mengerti bagaimana rel menangani urutan kompilasi aset, tetapi jelas tidak menguntungkan saya. Tampaknya tidak ada file yang menyadari bahwa mereka memiliki variabel atau mixin yang diimpor, sehingga menimbulkan kesalahan dan saya tidak dapat mengkompilasi.

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)

Variabel $dialog_divider_colordidefinisikan dengan jelas di _colors.css.scss, dan _master.css.scssmengimpor warna dan semua mixin saya. Tapi rupanya rel tidak mendapatkan memo itu.

Apakah ada cara agar saya dapat memperbaiki kesalahan ini, atau apakah saya perlu menggunakan semua definisi variabel saya kembali ke setiap file individual, serta semua impor mixin?

Sayangnya, orang ini sepertinya tidak berpikir itu mungkin, tapi saya berharap dia salah. Pikiran apa pun sangat dihargai.

David Savage
sumber

Jawaban:

126

Masalah dengan CSS adalah, Anda tidak ingin menambahkan semua file secara otomatis. Urutan saat sheet Anda dimuat dan diproses oleh browser sangatlah penting. Jadi Anda akan selalu mengimpor semua css Anda secara eksplisit.

Sebagai contoh, katakanlah Anda memiliki lembar normalize.css , untuk mendapatkan tampilan default alih-alih semua implementasi browser yang berbeda. Ini harus menjadi file pertama yang dimuat browser. Jika Anda memasukkan sheet ini secara acak di suatu tempat dalam impor css, itu tidak hanya akan menimpa gaya default browser, tetapi juga gaya apa pun yang ditentukan dalam semua file css yang dimuat sebelumnya. Ini berlaku sama untuk variabel dan mixin.

Setelah melihat presentasi oleh Roy Tomeij di Euruko2012 saya memutuskan untuk pendekatan berikut jika Anda memiliki banyak CSS untuk dikelola.

Saya biasanya menggunakan pendekatan ini:

  1. Ubah nama semua file .css yang ada menjadi .scss
  2. Hapus semua konten dari application.scss

Mulai tambahkan arahan @import ke application.scss.

Jika Anda menggunakan bootstrap twitters dan beberapa lembar css Anda sendiri, Anda harus mengimpor bootstrap terlebih dahulu, karena memiliki lembar untuk mengatur ulang gaya. Jadi Anda menambahkan @import "bootstrap/bootstrap.scss";untuk Anda application.scss.

File bootstrap.scss terlihat seperti:

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

Dan application.scssfile Anda terlihat seperti:

@import "bootstrap/bootstrap.scss";

Karena urutan impor, Anda sekarang dapat menggunakan variabel, dimuat dengan file @import "variables.scss";lain yang .scssdiimpor setelahnya. Jadi mereka bisa digunakan di type.scssdalam folder bootstrap tetapi juga di file my_model.css.scss.

Setelah ini buat folder bernama partialsatau modules. Ini akan menjadi tempat sebagian besar file lainnya. Anda tinggal menambahkan impor ke application.scssfile sehingga akan terlihat seperti:

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

Sekarang jika Anda membuat sedikit css untuk menata artikel di beranda Anda. Buat saja partials/_article.scssdan itu akan ditambahkan ke file application.css. Karena urutan impor, Anda juga dapat menggunakan mixin dan variabel bootstrap apa pun di file scss Anda sendiri.

Satu-satunya kelemahan dari metode ini yang saya temukan sejauh ini adalah, terkadang Anda harus memaksa kompilasi ulang sebagian file / * .scss karena rails tidak akan selalu melakukannya untuk Anda.

Benjamin Udink ten Cate
sumber
4
Terima kasih, ini adalah pendekatan yang akhirnya saya lakukan. Saya benci solusi ini karena Anda harus menambahkan setiap file secara manual yang Anda sertakan setiap kali Anda membuatnya, tetapi tampaknya ketika CSS terlibat, urutan itu penting. Biasanya saya akan mengatakan itu hanya penulisan CSS yang buruk, tetapi jika Anda menggunakan hal-hal yang disediakan vendor (yaitu bootstrap seperti yang Anda sebutkan di atas), Anda cenderung ingin menimpa sesuatu, jadi dengan enggan saya setuju ini adalah pendekatan yang tepat.
David Savage
1
Terima kasih! Pendekatan yang sangat bagus dan penjelasan yang bagus! Satu proyek yang patut disebutkan: Plugin FireBug ini, FireSass , menunjukkan nomor baris my_model.css.sass alih-alih baris application.css yang dikompilasi
BBQ Chef
Dengan pendekatan ini, jika saya ingin mengubah warna tautan default saya menjadi merah yang berlaku untuk semua parsial saya, bagaimana Anda melakukannya? Di mana Anda akan menaruhnya?
chh
1
Perhatikan bahwa pendekatan ini juga direkomendasikan dalam The Asset Pipeline Rails Guide . Cari "Jika Anda ingin menggunakan beberapa file Sass".
ybakos
1
@Lykos ya Anda menghapus semuanya dari application.cssdan mengubah namanya menjadi application.scss. Karena require_treehanya mencakup semuanya dan Anda biasanya ingin mengontrol pesanan
Benjamin Udink ten Cate
8

untuk menggunakan variabel dan sejenisnya di seluruh file, Anda perlu menggunakan direktif @import. file diimpor sesuai urutan yang ditentukan.

kemudian, gunakan application.css untuk meminta file yang mendeklarasikan impor. inilah cara untuk mencapai kendali yang Anda inginkan.

terakhir, dalam file layout.erb, Anda dapat menentukan file css "master" mana yang akan digunakan

contoh akan lebih membantu:

misalkan Anda memiliki dua modul di aplikasi Anda yang membutuhkan kumpulan css yang berbeda: "application" dan "admin"

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

inilah tampilan file di dalamnya:

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

Buat struktur folder berikut:

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

Dalam folder basebuat file "globals.css.scss". Di file ini, nyatakan semua impor Anda:

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

Di application.css.scss, Anda harus memiliki:

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

Dan sebagai langkah terakhir (ini penting), nyatakan @import 'base/globals'di setiap file gaya di mana Anda ingin menggunakan variabel atau mixin. Anda mungkin mempertimbangkan overhead ini, tetapi saya sebenarnya menyukai gagasan bahwa Anda harus mendeklarasikan dependensi gaya Anda di setiap file. Tentu saja, Anda hanya perlu mengimpor mixin dan variabel di globals.css.scss karena mereka tidak menambahkan definisi gaya. Jika tidak, definisi gaya akan disertakan beberapa kali dalam file yang telah dikompilasi sebelumnya ...

emrass
sumber
Saya mencoba ini tetapi tidak pernah bisa membuatnya berfungsi dengan baik (masih mendapatkan kesalahan variabel yang hilang). Mungkin saya tidak melakukan sesuatu dengan benar, tetapi saya pikir pada akhirnya pendekatan secara manual mendaftar setiap file adalah cara yang tepat, karena dengan urutan CSS itu penting.
David Savage
Anda masih bisa menggunakan pendekatan ini: Daripada "require_tree ..." cukup tambahkan satu baris untuk setiap file individual. Ini akan membuat SASS mengimpor file dalam urutan yang benar. Mengenai solusi yang Anda gunakan sekarang, silakan lihat posting ini yang baru saja saya temukan: stackoverflow.com/questions/7046495/… Pastikan untuk menyertakan directivie depend_on di file application.css Anda.
emrass
4

Menurut pertanyaan ini , Anda HANYA dapat menggunakan application.css.sassuntuk menentukan variabel impor dan berbagi di antara template Anda.

=> Sepertinya hanya masalah nama.

Cara lain adalah memasukkan semuanya dan menonaktifkan pipeline ini .

Coren
sumber
Ini pada dasarnya adalah hal yang sama yang ditawarkan Benjamin Udink ten Cate di bagian kedua dari tanggapan Anda, tetapi memberinya hadiah karena solusinya lebih jelas.
David Savage
1

Saya punya masalah yang sangat mirip. Yang membantu saya adalah memasukkan garis bawah ke pernyataan @import saat mengimpor parsial. Begitu

@import "_base";

dari pada

@import "base";

Ini mungkin bug yang aneh ...

Bernát
sumber