Estructura de activos de SCSS adecuada en rieles

86

Entonces, tengo una app/assets/stylesheets/estructura de directorio que se parece a esto:

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

En cada directorio, hay varios parciales sass (normalmente * .css.scss, pero uno o dos * .css.scss.erb).

Podría estar asumiendo mucho, pero los rieles DEBERÍAN compilar automáticamente todos los archivos en esos directorios debido a *= require_tree .en application.css, ¿verdad?

Recientemente intenté reestructurar estos archivos eliminando todas las variables de color y colocándolas en un archivo en la app/assets/stylesheetscarpeta raíz (_colors.css.scss). Luego creé un archivo en la app/assets/stylesheetscarpeta raíz llamado master.css.scss que se ve así:

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

Realmente no entiendo cómo rieles maneja el orden de compilación de activos, pero obviamente no está a mi favor. Parece que ninguno de los archivos se da cuenta de que se están importando variables o mixins, por lo que arroja errores y no puedo 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)

La variable $dialog_divider_colorestá claramente definida en _colors.css.scss, y _master.css.scssestá importando colores y todos mis mixins. Pero aparentemente Rails no recibió ese memo.

¿Hay alguna forma de corregir estos errores, o tendré que recurrir a volver a poner todas mis definiciones de variables en cada archivo individual, así como todas las importaciones de mixin?

Desafortunadamente, este tipo no parece pensar que sea posible, pero espero que esté equivocado. Cualquier idea es grandemente apreciada.

David Savage
fuente

Respuestas:

126

El problema con CSS es que no desea agregar automáticamente todos los archivos. El orden en el que el navegador carga y procesa las hojas es fundamental. Por lo tanto, siempre terminará importando explícitamente todos sus archivos css.

Como ejemplo, digamos que tiene una hoja normalize.css , para obtener un aspecto predeterminado en lugar de todas las horribles implementaciones de navegador diferentes. Este debería ser el primer archivo que cargue el navegador. Si incluye aleatoriamente esta hoja en algún lugar de sus importaciones css, no solo anulará los estilos predeterminados del navegador, sino también cualquier estilo definido en todos los archivos css que se cargaron antes. Esto es lo mismo para variables y mixins.

Después de ver una presentación de Roy Tomeij en Euruko2012, me decidí por el siguiente enfoque si tienes mucho CSS que administrar.

Generalmente uso este enfoque:

  1. Cambiar el nombre de todos los archivos .css existentes a .scss
  2. Eliminar todo el contenido de application.scss

Comience a agregar directivas @import a application.scss.

Si está utilizando bootstrap de Twitter y algunas hojas css propias, primero debe importar bootstrap, porque tiene una hoja para restablecer estilos. Entonces agregas @import "bootstrap/bootstrap.scss";a tu application.scss.

El archivo bootstrap.scss se ve así:

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

Y su application.scssarchivo se ve así:

@import "bootstrap/bootstrap.scss";

Debido al orden de las importaciones, ahora puede usar las variables, cargadas @import "variables.scss";en cualquier otro .scssarchivo importado después. Por lo tanto, se pueden usar type.scssen la carpeta de arranque, pero también en my_model.css.scss.

Después de esto, cree una carpeta llamada partialso modules. Este será el lugar de la mayoría de los otros archivos. Simplemente puede agregar la importación al application.scssarchivo para que se vea así:

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

Ahora, si crea un poco de CSS para diseñar un artículo en su página de inicio. Simplemente cree partials/_article.scssy se agregará al archivo application.css. Debido al orden de importación, también puede utilizar cualquier mixins y variables de arranque en sus propios archivos scss.

El único inconveniente que encontré hasta ahora de este método es que a veces tienes que forzar una recompilación de los archivos / *. Scss parciales porque los rieles no siempre lo harán por ti.

Benjamin Udink ten Cate
fuente
4
Gracias, este es el enfoque con el que terminé. Odio esta solución porque tiene que agregar manualmente todos los archivos que incluye cada vez que crea uno, pero parece que cuando se trata de CSS, el orden sí importa. Normalmente diría que es simplemente una mala escritura de CSS, pero si estás usando cosas que son proporcionadas por el proveedor (es decir, bootstrap como mencionaste anteriormente), tiendes a querer sobrescribir las cosas, así que estoy de acuerdo a regañadientes que este es el enfoque correcto.
David Savage
1
¡Gracias! ¡Un enfoque muy agradable y una buena explicación! Un proyecto que vale la pena mencionar: este complemento de FireBug, FireSass , muestra el número de línea de my_model.css.sass en lugar de la línea del archivo application.css compilado
BBQ Chef
Con este enfoque, si quiero cambiar el color de mi enlace predeterminado a rojo que se aplica a todos mis parciales, ¿cómo lo haría? ¿Dónde lo pondrías?
chh
1
Tenga en cuenta que este enfoque también se recomienda en The Asset Pipeline Rails Guide . Busque "Si desea utilizar varios archivos Sass".
ybakos
1
@Lykos sí, eliminas todo del application.cssy le cambias el nombre a application.scss. Porque require_treeincluye todo y normalmente quieres controlar el orden
Benjamin Udink ten Cate
8

para usar variables y similares en todos los archivos, debe usar la directiva @import. los archivos se importan en el orden especificado.

luego, use application.css para solicitar el archivo que declara las importaciones. esta es la forma de lograr el control que desea.

finalmente, en su archivo layout.erb, puede especificar qué archivo CSS "maestro" usar

El ejemplo será más útil:

digamos que tiene dos módulos en su aplicación que necesitan diferentes conjuntos de css: "aplicación" y "administrador"

Los archivos

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

así es como se ven los archivos en el interior:

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

Cree la siguiente estructura de carpetas:

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

En la carpeta basecree un archivo "globals.css.scss". En este archivo, declare todas sus importaciones:

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

En su application.css.scss, debería tener:

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

Y como último paso (esto es importante), declare @import 'base/globals'en cada archivo de estilo dónde desea usar variables o mixins. Puede considerar esta sobrecarga, pero en realidad me gusta la idea de que debe declarar las dependencias de sus estilos en cada archivo. Por supuesto, es importante que solo importe mixins y variables en globals.css.scss ya que no agregan definiciones de estilo. De lo contrario, las definiciones de estilo se incluirían varias veces en su archivo precompilado ...

emrass
fuente
Probé esto pero nunca pude hacer que funcionara correctamente (todavía aparecían errores de variables faltantes). Tal vez no hice algo correctamente, pero creo que al final el enfoque de enumerar manualmente cada archivo es el camino correcto, ya que con CSS el orden sí importa.
David Savage
Aún puede usar este enfoque: en lugar de "require_tree ..." simplemente agregue una línea para cada archivo individual. Esto hará que SASS importe los archivos en el orden correcto. Con respecto a la solución que está utilizando ahora, eche un vistazo a esta publicación que acabo de encontrar: stackoverflow.com/questions/7046495/… Asegúrese de incluir la directiva depend_on en su archivo application.css.
emrass
4

De acuerdo con esta pregunta , SOLO puede usar application.css.sasspara definir importar y compartir variables entre sus plantillas.

=> Parece ser solo una cuestión de nombre.

Otra forma puede ser incluir todo y deshabilitar esta canalización .

Coren
fuente
Esto es esencialmente lo mismo que Benjamin Udink ten Cate ofreció en la segunda parte de su respuesta, pero otorgarle la recompensa como su solución es más explicativo.
David Savage
1

Tuve un problema muy similar. Lo que me ayudó fue poner el guión bajo en la declaración @import al importar el parcial. Entonces

@import "_base";

en vez de

@import "base";

Podría ser un error extraño ...

Bernát
fuente