Правильная структура активов SCSS в Rails

86

Итак, у меня есть app/assets/stylesheets/структура каталогов, которая выглядит примерно так:

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

В каждом каталоге есть несколько партиалов sass (обычно * .css.scss, но один или два * .css.scss.erb).

Я могу предположить многое, но rails ДОЛЖЕН автоматически компилировать все файлы в этих каталогах из-за файла *= require_tree .application.css, верно?

Недавно я попытался реструктурировать эти файлы, удалив все цветовые переменные и поместив их в файл в корневой app/assets/stylesheetsпапке (_colors.css.scss). Затем я создал в корневой app/assets/stylesheetsпапке файл с именем master.css.scss, который выглядит так:

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

Я действительно не понимаю, как rails обрабатывает порядок компиляции ассетов, но это явно не в мою пользу. Похоже, что ни один из файлов не осознает, что у них есть какие-либо импортируемые переменные или миксины, поэтому он выдает ошибки, и я не могу скомпилировать.

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)

Переменная $dialog_divider_colorчетко определена в _colors.css.scss и _master.css.scssимпортирует цвета и все мои миксины. Но, видимо, эту памятку Рилс не получил.

Есть ли способ исправить эти ошибки, или мне придется прибегать к возвращению всех моих определений переменных обратно в каждый отдельный файл, а также ко всему импорту миксинов?

К сожалению, этот парень не думает, что это возможно, но я надеюсь, что он ошибается. Любые мысли приветствуются.

Дэвид Сэвидж
источник

Ответы:

126

Проблема с CSS в том, что вы не хотите автоматически добавлять все файлы. Порядок, в котором ваши листы загружаются и обрабатываются браузером, очень важен. Таким образом, вы всегда будете явно импортировать все свои css.

В качестве примера допустим, что у вас есть лист normalize.css , чтобы получить вид по умолчанию вместо всех ужасных реализаций браузера. Это должен быть первый файл, загружаемый браузером. Если вы просто случайным образом включите этот лист где-нибудь в свой импорт css, тогда он переопределит не только стили браузера по умолчанию, но также любые стили, определенные во всех файлах css, которые были загружены до него. То же самое для переменных и миксинов.

Увидев презентацию Роя Томейджа на Euruko2012, я решил использовать следующий подход, если вам нужно управлять большим количеством CSS.

Обычно я использую такой подход:

  1. Переименуйте все существующие файлы .css в .scss
  2. Удалите все содержимое из application.scss

Начните добавлять директивы @import в application.scss.

Если вы используете загрузку твиттера и несколько собственных таблиц css, вам необходимо сначала импортировать загрузочную страницу, потому что в ней есть лист для сброса стилей. Итак, вы добавляете @import "bootstrap/bootstrap.scss";в свой application.scss.

Файл bootstrap.scss выглядит так:

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

И ваш application.scssфайл выглядит так:

@import "bootstrap/bootstrap.scss";

Из-за порядка импорта теперь вы можете использовать переменные, загруженные @import "variables.scss";в любой другой .scssфайл, импортированный после него. Таким образом, их можно использовать type.scssв папке начальной загрузки, а также в my_model.css.scss.

После этого создайте папку с именем partialsили modules. Это будет место для большинства других файлов. Вы можете просто добавить импорт в application.scssфайл, чтобы он выглядел так:

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

Теперь, если вы сделаете немного CSS для стилизации статьи на своей домашней странице. Просто создайте, partials/_article.scssи он будет добавлен в скомпилированный application.css. Из-за порядка импорта вы также можете использовать любые примеси и переменные начальной загрузки в своих собственных файлах scss.

Единственный недостаток этого метода, который я обнаружил до сих пор, заключается в том, что иногда вам нужно принудительно перекомпилировать частичные файлы / *. Scss, потому что rails не всегда делают это за вас.

Бенджамин Удинк тен Кейт
источник
4
Спасибо, я выбрал именно такой подход. Я ненавижу это решение, потому что вам нужно вручную добавлять каждый файл, который вы включаете, каждый раз, когда вы его создаете, но кажется, что когда задействован CSS, порядок имеет значение. Обычно я бы сказал, что это просто плохое написание CSS, но если вы используете вещи, предоставленные поставщиком (например, начальную загрузку, как вы упомянули выше), вы, как правило, захотите перезаписать вещи, поэтому я неохотно согласен, что это правильный подход.
Дэвид Сэвидж,
1
Благодарность! Очень хороший подход и хорошее объяснение! Стоит упомянуть один проект: этот плагин FireBug, FireSass , показывает номер строки my_model.css.sass вместо строки скомпилированного application.css
BBQ Chef
При таком подходе, если я хочу изменить цвет ссылки по умолчанию на красный, который применяется ко всем моим частичным параметрам, как бы вы это сделали? Куда бы вы его положили?
чч
1
Обратите внимание, что этот подход также рекомендуется в The Asset Pipeline Rails Guide . Найдите «Если вы хотите использовать несколько файлов Sass».
ybakos 01
1
@Lykos да, вы удалите все из файла application.cssи переименуйте его в application.scss. Потому что require_treeвключает в себя все, и вы обычно хотите контролировать порядок
Бенджамин Удинк тен Кейт
8

чтобы использовать переменные и тому подобное в файлах, вам необходимо использовать директиву @import. файлы импортируются в указанном порядке.

затем используйте application.css, чтобы запросить файл, объявляющий импорт. это способ добиться желаемого контроля.

наконец, в файле layout.erb вы можете указать, какой "главный" файл css использовать

пример будет более полезным:

допустим, у вас есть два модуля в вашем приложении, которым нужны разные наборы CSS: «application» и «admin»

файлы

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

вот как файлы выглядят внутри:

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

Создайте следующую структуру папок:

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

В папке baseсоздайте файл "globals.css.scss". В этом файле объявите весь свой импорт:

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

В вашем application.css.scss вы должны иметь:

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

И в качестве последнего шага (это важно) объявите @import 'base/globals'в каждом файле стилей, где вы хотите использовать переменные или миксины. Вы можете подумать об этих накладных расходах, но мне действительно нравится идея, что вы должны объявлять зависимости ваших стилей в каждом файле. Конечно, важно, чтобы вы импортировали только миксины и переменные в globals.css.scss, поскольку они не добавляют определения стилей. В противном случае определения стилей будут включены несколько раз в ваш предварительно скомпилированный файл ...

Emrass
источник
Я попробовал это, но так и не смог заставить его работать должным образом (все еще возникали ошибки с отсутствующими переменными). Возможно, я что-то сделал неправильно, но я думаю, что в конце концов подход вручную перечислить каждый файл - это правильный путь, поскольку порядок CSS имеет значение.
Дэвид Сэвидж
Вы все еще можете использовать этот подход: вместо «require_tree ...» просто добавьте строку для каждого отдельного файла. Это заставит SASS импортировать файлы в правильном порядке. Что касается решения, которое вы сейчас используете, ознакомьтесь с этим сообщением, которое я только что нашел: stackoverflow.com/questions/7046495/… Убедитесь, что вы включили директиву depends_on в файл application.css.
emrass
4

Согласно этому вопросу , вы можете использовать ТОЛЬКОapplication.css.sass для определения переменных импорта и обмена между вашими шаблонами.

=> Кажется, дело только в названии.

Другой способ - включить все и отключить этот конвейер .

Корен
источник
По сути, это то же самое, что Бенджамин Удинк тен Кейт предложил во второй части вашего ответа, но присуждение ему награды как его решения является более пояснительным.
Дэвид Сэвидж,
1

У меня была очень похожая проблема. Мне помогло то, что при импорте партиала в оператор @import был подчеркнут символ подчеркивания. Так

@import "_base";

вместо того

@import "base";

Это может быть странная ошибка ...

Бернат
источник