Estrutura de ativos SCSS adequada em Rails

86

Portanto, tenho uma app/assets/stylesheets/estrutura de diretório semelhante a esta:

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

Em cada diretório, há vários parciais de sass (normalmente * .css.scss, mas um ou dois * .css.scss.erb).

Posso estar supondo muito, mas o rails DEVE compilar automaticamente todos os arquivos nesses diretórios por causa de *= require_tree .em application.css, certo?

Recentemente, tentei reestruturar esses arquivos removendo todas as variáveis ​​de cores e colocando-as em um arquivo na app/assets/stylesheetspasta raiz (_colors.css.scss). Em seguida, criei um arquivo na app/assets/stylesheetspasta raiz chamado master.css.scss que se parece com este:

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

Eu realmente não entendo como o rails lida com a ordem de compilação de ativos, mas obviamente não é a meu favor. Parece que nenhum dos arquivos percebe que eles têm alguma variável ou mixins sendo importados, e por isso gera erros e não consigo compilar.

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)

A variável $dialog_divider_colorestá claramente definida em _colors.css.scss e _master.css.scssestá importando cores e todos os meus mixins. Mas aparentemente o Rails não recebeu esse memorando.

Existe alguma maneira de corrigir esses erros, ou vou precisar recorrer a colocar todas as minhas definições de variáveis ​​de volta em cada arquivo individual, bem como todas as importações do mixin?

Infelizmente, esse cara não parece pensar que isso seja possível, mas espero que ele esteja errado. Quaisquer pensamentos são muito apreciados.

David Savage
fonte

Respostas:

126

O problema com CSS é que você não deseja adicionar todos os arquivos automaticamente. A ordem em que suas folhas são carregadas e processadas pelo navegador é essencial. Assim, você sempre acabará importando explicitamente todos os seus css.

Como exemplo, digamos que você tenha uma planilha normalize.css , para obter uma aparência padrão em vez de todas as horríveis implementações de navegador diferentes. Este deve ser o primeiro arquivo que o navegador carrega. Se você incluir esta planilha aleatoriamente em algum lugar em suas importações de css, ela não apenas substituirá os estilos padrão do navegador, mas também quaisquer estilos definidos em todos os arquivos css que foram carregados antes dela. O mesmo vale para variáveis ​​e mixins.

Depois de ver uma apresentação de Roy Tomeij no Euruko2012, decidi pela seguinte abordagem se você tem muito CSS para gerenciar.

Eu geralmente uso esta abordagem:

  1. Renomeie todos os arquivos .css existentes para .scss
  2. Remova todo o conteúdo de application.scss

Comece a adicionar diretivas @import a application.scss.

Se você estiver usando twitters bootstrap e algumas folhas css próprias, você deve importar primeiro o bootstrap, porque ele tem uma folha para redefinir os estilos. Então você adiciona @import "bootstrap/bootstrap.scss";ao seu application.scss.

O arquivo bootstrap.scss se parece com:

// 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 seu application.scssarquivo se parece com:

@import "bootstrap/bootstrap.scss";

Por causa da ordem das importações, agora você pode usar as variáveis, carregadas com @import "variables.scss";em qualquer outro .scssarquivo importado depois disso. Portanto, eles podem ser usados ​​na type.scsspasta de bootstrap, mas também em my_model.css.scss.

Depois disso, crie uma pasta chamada partialsou modules. Este será o local da maioria dos outros arquivos. Você pode simplesmente adicionar a importação ao application.scssarquivo para que fique assim:

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

Agora, se você fizer um pouco de css para estilizar um artigo em sua página inicial. Basta criar partials/_article.scsse ele será adicionado ao compilado application.css. Por causa da ordem de importação, você também pode usar qualquer mixins e variáveis ​​de bootstrap em seus próprios arquivos scss.

A única desvantagem desse método que encontrei até agora é que às vezes você tem que forçar uma recompilação dos arquivos / *. Scss parciais porque o rails nem sempre fará isso por você.

Benjamin Udink ten Cate
fonte
4
Obrigado, esta é a abordagem que acabei escolhendo. Eu odeio essa solução porque você tem que adicionar manualmente cada arquivo que está incluindo sempre que cria um, mas parece que, quando o CSS está envolvido, a ordem importa. Normalmente, eu diria que isso é apenas uma escrita CSS incorreta, mas se você estiver usando coisas fornecidas pelo fornecedor (ou seja, inicializar como mencionou acima), você tende a querer sobrescrever as coisas, então, relutantemente, concordo que essa é a abordagem certa.
David Savage
1
Obrigado! Uma abordagem muito boa e uma boa explicação! Um projeto que vale a pena mencionar: este plugin FireBug, FireSass , mostra o número da linha de my_model.css.sass em vez da linha do application.css compilado
BBQ Chef
Com essa abordagem, se eu quiser alterar minha cor de link padrão para vermelho que se aplica a todas as minhas parciais, como você faria isso? Onde você colocaria?
chh
1
Observe que essa abordagem também é recomendada no The Asset Pipeline Rails Guide . Pesquise por "Se você deseja usar vários arquivos Sass".
ybakos 01 de
1
@Lykos sim, você remove tudo do application.csse renomeia para application.scss. Porque require_treeinclui apenas tudo e você geralmente deseja controlar o pedido
Benjamin Udink ten Cate
8

para usar variáveis ​​e outros semelhantes em arquivos, você precisa usar a diretiva @import. os arquivos são importados na ordem especificada.

em seguida, use o application.css para solicitar o arquivo que declara as importações. esta é a maneira de obter o controle que você deseja.

finalmente, em seu arquivo layout.erb, você pode especificar qual arquivo css "mestre" usar

exemplo será mais útil:

digamos que você tenha dois módulos em seu aplicativo que precisam de conjuntos diferentes de css: "aplicativo" e "admin"

os arquivos

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

aqui está a aparência dos arquivos por dentro:

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

Crie a seguinte estrutura de pastas:

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

Na pasta, basecrie um arquivo "globals.css.scss". Neste arquivo, declare todas as suas importações:

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

Em seu application.css.scss, você deve ter:

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

E como último passo (isso é importante), declare @import 'base/globals'em cada arquivo de estilo onde você deseja usar variáveis ​​ou mixins. Você pode considerar essa sobrecarga, mas na verdade gosto da ideia de que você tem que declarar as dependências de seus estilos em cada arquivo. Obviamente, é importante que você importe apenas mixins e variáveis ​​em globals.css.scss, pois eles não adicionam definições de estilo. Caso contrário, as definições de estilo seriam incluídas várias vezes em seu arquivo pré-compilado ...

Emrass
fonte
Eu tentei fazer isso, mas nunca consegui fazer funcionar corretamente (ainda estava recebendo erros de variável ausente). Talvez eu não tenha feito algo corretamente, mas acho que no final das contas a abordagem de listar manualmente cada arquivo é o caminho certo a seguir, já que com o CSS a ordem é importante.
David Savage
Você ainda pode usar esta abordagem: Em vez de "require_tree ...", apenas adicione uma linha para cada arquivo individual. Isso fará com que o SASS importe os arquivos na ordem correta. Com relação à solução que você está usando agora, dê uma olhada neste post que acabei de encontrar: stackoverflow.com/questions/7046495/… Certifique-se de incluir a diretiva depends_on em seu arquivo application.css.
emrass
4

De acordo com esta questão , você pode usar SOMENTEapplication.css.sass para definir variáveis ​​de importação e compartilhamento entre seus modelos.

=> Parece ser apenas uma questão de nome.

Outra forma pode ser incluir tudo e desabilitar este pipeline .

Coren
fonte
Esta é essencialmente a mesma coisa que Benjamin Udink ten Cate ofereceu na segunda parte de sua resposta, mas conceder a ele a recompensa por sua solução é mais explicativo.
David Savage
1

Eu tive um problema muito parecido. O que me ajudou foi colocar o sublinhado na instrução @import ao importar o parcial. então

@import "_base";

ao invés de

@import "base";

Pode ser um bug estranho ...

Bernát
fonte