#268 Sass Basics
- Download:
- source codeProject Files in Zip (80.5 KB)
- mp4Full Size H.264 Video (27.7 MB)
- m4vSmaller H.264 Video (15 MB)
- webmFull Size VP8 Video (16.5 MB)
- ogvFull Size Theora Video (38 MB)
Uno de los cambios más importantes que incorpora la próxima versión de Rails 3.1 es el soporte de SASS, que se incorpora por defecto como forma de generar ficheros CSS. SASS proporciona varias funcionalidades que facilita la gestión de las hojas de estilo de una aplicación de entre las que cabe destacar la posibilidad de anidar reglas, definir variables y otras mejoras que no pertenecen al estándar de CSS. En este episodio veremos las ventajas de convertir una hoja de estilos CSS a SASS con Rails 3.1.
El sitio con el que vamos a trabajar tiene el siguiente aspecto:
Ahora mismo todos los estilos se están aplicando mediante CSS y nuestro objetivo es convertir dichas hojas de estilo a SASS haciendo que el sitio tenga el mismo aspecto. La hoja de estilos de la que partimos es la siguiente:
body { margin: 0; padding: 0; background-color: #FFF; font-family: verdana; font-size: 14px; } #header { background-color: #03507B; color: #FFF; padding: 4px 100px; border-bottom: solid 5px #00395A; } #header h1 { font-size: 30px; } a { color: #03507B; text-decoration: none; } a:hover { text-decoration: underline; } .new_project { background-color: #03507B; color: #FFF; padding: 5px 12px; margin: 10px 0; font-size: 16px; border-radius: 5px; -moz-border-radius: 5px; -webkit-border-radius: 5px; } #container { margin: 0 100px; } .project { border: solid 1px #777; margin: 20px 0; padding: 7px 12px; border-radius: 10px; -moz-border-radius: 10px; -webkit-border-radius: 10px; } .project h2 { margin: 0; }
No se trata de una hoja de estilos especialmente complicada por lo que debería ser relativamente sencillo convertir su código a SASS. El primero paso es añadir al fichero la extensión .scss
. El código CSS normal es compatible con SASS, por lo que si recargamos la página en el navegador todo debería seguir viéndose igual.
Y con esto nuestra aplicación ya esta utilizando SASS. ¿Eso es todo? Está claro que no, pero viene muy bien que CSS siga estando totalmente soportado porque esto significa que podemos ir escogiendo qué prestaciones de SASS queremos ir incorporando. Si tenemos un sitio con muchos ficheros CSS podríamos renombrarlos y empezar a modificarlos introduciendo los cambios de SASS que nos interesen... que serán muchos una vez que hayamos terminado de ver sus ventajas en este episodio.
Anidamiento
La primera funcionalidad de SASS que veremos en nuestra hoja de estilos es el anidamiento. Veamos el siguiente fragmento de CSS:
#header { background-color: #03507B; color: #FFF; padding: 4px 100px; border-bottom: solid 5px #00395A; } #header h1 { font-size: 30px; }
Con este código definimos los estilos para un elemento que tenga un identificador llamado header
y para cualquier elemento h1
dentro de dicho elemento. En SASS podemos anidar los estilos de h1
dentro de los estilos de #header
de esta forma:
#header { background-color: #03507B; color: #FFF; padding: 4px 100px; border-bottom: solid 5px #00395A; h1 { font-size: 30px; } }
Lo que quiere decir que no tenemos que especificar un prefijo para los elementos anidados y nos anima a tener juntos los elementos anidados. Es mejor emplear anidamientos sencillos para evitar que se nos vaya la mano y acabemos con un código CSS muy largo y complejo. Si lo hacemos así podremos ver de un vistazo qué está anidado bajo qué. Por supuesto no se trata de una regla para seguir al pie de la letra y tendremos que experimentar con nuestros propios estilos hasta dar con el nivel de anidamiento que mejor se adapte a nuestro trabajo.
También podemos usar el anidamiento autoreferenciado en nuestros estilos. En el código CSS tenemos un selector para el elemento a
y otro para a:hover
.
a { color: #03507B; text-decoration: none; } a:hover { text-decoration: underline; }
Podríamos anidarlos pero como a:hover
realmente no es un elemento anidado tenemos que añadir un ampersand para representar el elemento padre.
a { color: #03507B; text-decoration: none; &:hover { text-decoration: underline; } }
Este símbolo es necesario porque estamos aplicando los estilos a un atributo de un elemento más que a un elemento anidado propiamente dicho.
Variables
Otra utilidad de SASS es la de poder definir variables. Por ejemplo, en nuestro fichero CSS utilizamos el mismo color varias veces. Si quisiéramos cambiar dicho color en todo el site tendríamos que cambiar el fichero CSS tantas veces como aparezca dicho color.
Todo esto es más fácil con SASS porque podemos definir variables. Los nombres de variable en SASS empieza con el símbolo del dolar por lo que podemos definir una variable para nuestro color así:
$main-color: #03507B;
Ya podemos cambiar cualquier referencia a dicho color por la variable:
$main-color: #03507B; #header { background-color: $main-color; color: #FFF; padding: 4px 100px; border-bottom: solid 5px #00395A; h1 { font-size: 30px; } } a { color: $main-color; text-decoration: none; &:hover { text-decoration: underline; } }
Si ahora recargamos la página veremos que tiene el mismo aspecto así que no se ha roto nada. Si queremos cambiar el color sólo tenemos que hacerlo en un único sitio y podemos cambiar el azul por verde modificando tan sólo una línea en la hoja de estilos.
$main-color: #1E7B12;
Si ahora recargamos la página veremos que cambian todos los estilos que usaban este color: el fondo del encabezamiento, los enlaces y el botón “New Project” ahora salen verdes y tan sólo hemos tenido que cambiar un color.
Pero el borde del fondo del encabezado sigue siendo azul oscuro, y queremos que sea de un tono más oscuro del que tiene el encabezado. SASS nos permite definir unos colores en relación a otros mediante el uso de funciones. En el sitio web de SASS se enumera la lista completa de funciones, entra las que figura una función para oscurecer un color que hace exactamente lo que queremos. Si le pasamos un color y un porcentaje devolverá un color oscurecido en dicha cantidad.
El color del borde inferior del encabezado se define en #header
.
#header { background-color: $main-color; color: #FFF; padding: 4px 100px; border-bottom: solid 5px #00395A; h1 { font-size: 30px; } }
Podemos cambiar el color azul oscuro por una llamada a darken
de forma que el borde sea del mismo color que el fondo del encabezamiento, pero un 10% más oscuro.
#header { background-color: $main-color; color: #FFF; padding: 4px 100px; border-bottom: solid 5px darken($main-color, 10%); h1 { font-size: 30px; } }
Si ahora recargamos la página el fondo azul cambia por un verde más oscuro.
Mix-ins
Los mix-ins son otra funcionalidad de SASS con la que podemos reducir la duplicidad. En nuestra hoja de estilo aparecen dos elementos que tienen un radio para el borde. Las definiciones de radios de borde son más complicadas de lo que deberían ser porque tenemos que declarar valores específicos para cada navegador si queremos que el borde redondeado se vea en todos ellos.
border-radius: 5px; -moz-border-radius: 5px; -webkit-border-radius: 5px;
Si nos llevamos este código a un mix-in nos será mucho más fácil añadir declaraciones de bordes redondeados. Los mix-in se definen con la palabra clave @mixin
y dándole un nombre para poder usarlo en otros sitios.
@mixin rounded-corners { border-radius: 5px; -moz-border-radius: 5px; -webkit-border-radius: 5px; }
Con esto ya podemos aplicar un borde redondeado donde queramos invocando a @include
.
.new_project { background-color: $main-color; color: #FFF; padding: 5px 12px; margin: 10px 0; font-size: 16px; @include rounded-corners; }
Tenemos otra declaración de border-radius
en nuestra hoja de estilos pero con un valor distinto para el radio. Por suerte los mix-ins pueden recibir argumentos por lo que podemos alterar nuestro mix-in para esquinas redondeadas para que tenga el siguiente aspecto:
@mixin rounded-corners($radius) { border-radius: $radius; -moz-border-radius: $radius; -webkit-border-radius: $radius; }
Le podemos pasar cualquier valor que queramos al definir unos bordes redondeados:
.project { border: solid 1px #777; margin: 20px 0; padding: 7px 12px; @include rounded-corners(10px); }
Si queremos especificar un valor por defecto podríamos hacerlo de la siguiente manera:
@mixin rounded-corners($radius: 5px) { border-radius: $radius; -moz-border-radius: $radius; -webkit-border-radius: $radius; }
SASS en múltiples archivos
Las hojas de estilos se pueden hacer muy largas y poco manejables incluso aunque estemos usando SASS para definirlas, así que veamos cómo podemos organizar los estilos poniéndolos en diferentes archivos. Ya tenemos projects.css.scss
en nuestra aplicación, el cual fue creado cuando generamos el andamiaje de Projects
. Por defecto este fichero vendrá vacio y podemos poner el código SASS que queramos para que sea incluido por Rails 3.1 en la compilación de la hoja de estilos CSS única.
Queremos mover todo el SASS relacionado con los proyectos al archivo projects.css.scss
. Veamos que pasa:
.new_project { background-color: $main-color; color: #FFF; padding: 5px 12px; margin: 10px 0; font-size: 16px; @include rounded-corners(5px); } .project { border: solid 1px #777; margin: 20px 0; padding: 7px 12px; @include rounded-corners(10px); } .project h2 { margin: 0; }
Si recargamos la página veremos que no se cargan estos estilos.
Podemos comprobar si ha habido un error de SASS bien mirando en el fichero de trazas o inspeccionando la hoja de estilos en el navegador.
Aquí podremos ver que hay un error de sintaxis en el código SASS que impide que la hoja de estilos se genere. En este caso tenemos un error acerca de una variable no definida:
Undefined variable: "$main-color".
Parece que la variable que estamos definiendo en nuestra hoja de estilos principal no se propaga entre ficheros SASS.
Este problema se debe a la forma en la que Sprockets funciona en Rails 3.1. Las variables no se comparten entre ficheros SASS y podemos ver por qué en nuestro fichero application.css
.
/* * This is a manifest file that'll automatically include all the stylesheets available in this directory * and any sub-directories. You're free to add application-wide styles to this file and they'll appear at * the top of the compiled file, but it's generally better to create a new file per style scope. *= require_self *= require_tree . */
La línea require_tree
le dice a Sprockets que incluya todos los archivos que cuelguen del directorio stylesheets
. El problema es que cada archivo SASS se compila por separado a su fichero CSS antes de combinarlos todos por lo que las variables de compilación no quedan compartidas. Para que esto funcione tenemos que quitar require_tree
y utilizar SASS para importar una a una cada hoja de estilo. Con este enfoque además tendremos la ventaja de que nos permite definir el orden en que se cargan los archivos, cosa que no podemos hacer cuando usamos require_tree
. Tenemos que renombrar el fichero application.css
a application.css.scss
y luego quitar la línea require_tree
e importar nuestras hojas de estilo manualmente.
/* * This is a manifest file that'll automatically include all the stylesheets available in this directory * and any sub-directories. You're free to add application-wide styles to this file and they'll appear at * the top of the compiled file, but it's generally better to create a new file per style scope. *= require_self */ @import "layout.css.scss"; @import "projects.css.scss";
Esto compartirá entre las hojas de estilo todas las variables, mix-ins y cualquier cosa que hayamos definido. Si ahora recargamos la página veremos que carga correctamente y que las variables definidas en la hoja de estilo principal están disponibles en la hoja de estilos de proyectos.
¿SCSS o SASS?
Cabría preguntarse por qué las hojas de estilo tienen la extensión .scss
si el lenguaje se llama SASS. Esto es debido a que SASS soporta dos sintaxis diferentes. SCSS es nuevo en SASS 3 pero la sintaxis antigua sigue estando disponible y además en un futuro seguirá estando soportada. Para usarla sólo tenemos que utilizar la extensión de archivo .sass
. La sintaxis de SASS es similar a la de SCSS pero no utiliza llaves o punto y coma al final de cada línea, usándose la indentación para indicar el nivel de anidamiento. Como la sintaxis de SCSS es un superconjunto de la de CSS, es más fácil de manejar si estamos migrando hojas de estilo CSS, pero la opción de usar uno u otro queda ahí.
Hojas de estilo condicionales
Cerraremos este episodio con un truco rápido. ¿Cómo podemos cambiar los archivos CSS que se incluyen basándonos en el controlador actual? Dado que tenemos una hoja de estilos llamada projects.css.scss
podríamos pensar que sólo sería incluida en las acciones de ProjectsController
, pero este no es el caso. Todo el CSS se compila en una gran hoja de estilos que se aplica en todas las páginas de la aplicación. Por lo general esto no es un problema si marcamos las herencias correctamente pero puede dar quebraderos algunas veces.
Una solución a esto es modificar la etiqueta de apertura de la etiqueta body
en el fichero de layout y añadir un id
cuyo valor sea igual que el nombre del controlador.
<body id="<%= params[:controller].parameterize %>_controller">
Hemos invocado a parameterize
sobre el nombre del controlador para elminar los caracteres no válidos que pueda tener. Ya tenemos un único id
para cada controlador que podemos usar como ámbito en nuestros ficheros SASS de la siguiente manera:
#projects_controller { .new_project { background-color: $main-color; color: #FFF; padding: 5px 12px; margin: 10px 0; font-size: 16px; @include rounded-corners(5px); } .project { border: solid 1px #777; margin: 20px 0; padding: 7px 12px; @include rounded-corners(10px); } .project h2 { margin: 0; } }
Los estilos definidos en esta hoja sólo serán aplicados en las acciones de ProjectsController
. Esto quiere decir que será más difícil que tengamos conflictos entre identificadores y clases similares entre diferentes controladores.
Con esto concluimos este capítulo dedicado a SASS. Por supuesto no nos ha dado tiempo a ver todo lo que SASS puede hacer, por lo que se recomienda mirar la documentación en la web de SASS.