Introducción
Si bien anteriormente hemos incluido la instalación y configuración de LESS, desde este momento nos centraremos tan solo en el uso de SASS y SCSS.
Por otra parte, habrás comprobado que NetBeans no es capaz de trabajar con archivos
*.sass; por este motivo, te recomiendo que realices los diferentes ejercicios con
*.scss, si bien en los ejemplos y en las soluciones se incluirán ambas opciones para el caso de que trabajes con un IDE más avanzado.
En este apartado introduciremos los siguientes conceptos:
- Anidamiento (Nesting) de estilos y propiedades
- Referencia a selectores padre
- Comentarios
- Selectores placeholder
- Funciones especiales
Anidamiento (Nesting) de estilos y propiedades
Ya sabemos que las reglas de estilo son la base de CSS, y lo mismo ocurre con Sass y SCSS, de modo que la declaración siguiente es válida tanto en CSS como en SCSS:
.button {
padding: 3px 10px;
font-size: 12px;
border-radius: 3px;
border: 1px solid #e1e4e8;
}
Y en Sass solo cambiaría por la sintaxis indentada:
.button
padding: 3px 10px
font-size: 12px
border-radius: 3px
border: 1px solid #e1e4e8
Sin embargo, con Sass/SCSS podemos mejorar mucho nuestras hojas de estilo si introducimos el concepto de
anidamiento o
nesting, que básicamente nos va a permitir anidar los estilos que correspondan a elementos hijos dentro de los estilos de sus padres, tal y como vimos en el ejercicio anterior:
SCSS
nav {
ul {
margin: 0;
padding: 0;
list-style: none;
}
li { display: inline-block; }
a {
display: block;
padding: 6px 12px;
text-decoration: none;
}
}
Sass
nav
ul
margin: 0
padding: 0
list-style: none
li
display: inline-block
a
display: block
padding: 6px 12px
text-decoration: none
CSS
nav ul {
margin: 0;
padding: 0;
list-style: none;
}
nav li {
display: inline-block;
}
nav a {
display: block;
padding: 6px 12px;
text-decoration: none;
}
No obstante debemos tener en cuenta que
el anidamiento excesivo de estilos se convertirá en hojas de estilo cada vez más complejas y poco manejables para el navegador, por lo que debemos realizar el anidamiento con precaución.
También es posible utilizar el
anidamiento para las listas de selectores, esto es, selectores separados por comas, ya que cada uno de estos selectores será anidado de manera separada y luego combinado de nuevo en la lista de selectores resultante:
SCSS
.alert, .warning {
ul, p {
margin-right: 0;
margin-left: 0;
padding-bottom: 0;
}
}
Sass
.alert, .warning
ul, p
margin-right: 0
margin-left: 0
padding-bottom: 0
CSS
.alert ul, .alert p, .warning ul, .warning p {
margin-right: 0;
margin-left: 0;
padding-bottom: 0;
}
Otra utilidad más avanzada de esta propiedad es usar el anidamiento para
selectores con combinadores (
>, *, ~, etc.), de modo que podemos poner dichos combinadores al final del selector exterior, al principio del selector interior o incluso entre los dos:
SCSS
ul > {
li {
list-style-type: none;
}
}
h2 {
+ p {
border-top: 1px solid gray;
}
}
p {
~ {
span {
opacity: 0.8;
}
}
}
Sass
ul >
li
list-style-type: none
h2
+ p
border-top: 1px solid gray
p
~
span
opacity: 0.8
CSS
ul > li { /* el elemento a ser afectado por la regla es el elemento de la derecha cuando tiene al de la izquierda como su padre */
list-style-type: none;
}
h2 + p { /* referencia al elemento de la derecha cuando es inmediatamente precedido por el de la izquierda */
border-top: 1px solid gray;
}
p ~ span { /* referencia al elemento de la derecha pero no necesita estar precediendo de inmediato al elemento de la izquierda y más de un elemento puede ser afectado */
opacity: 0.8;
}
Puedes refrescar el uso de estos selectores con combinador en mi clase
Hojas de estilo CSS, Referenciando con otros atributos.
Referencia a selectores padre
Otra utilidad interesante para combinar con el anidamiento es el uso del
selector de padre o
parent selector,
&, utilizado para referenciar al selector exterior del anidamiento:
SCSS
.alert {
/* Para añadir pseudo-clases al selector exterior */
&:hover {
font-weight: bold;
}
/* Para añadir un estilo al selector exterior en un determinado contexto (por ejemplo, un body con idioma de derecha a izquierda) */
[dir=rtl] & {
margin-left: 0;
margin-right: 10px;
}
/* Como argumento para selectores de pseudo-clases */
:not(&) {
opacity: 0.8;
}
/* Con sufijos */
&__copy {
display: none;
}
}
Sass
.alert
&:hover
font-weight: bold
[dir=rtl] &
margin-left: 0
margin-right: 10px
:not(&)
opacity: 0.8
&__copy
display: none
CSS
.alert:hover {
font-weight: bold;
}
[dir=rtl] .alert {
margin-left: 0;
margin-right: 10px;
}
:not(.alert) {
opacity: 0.8;
}
.alert__copy {
display: none;
}
Comentarios
Los comentarios en
SCSS funcionan de forma similar a los de JavaScript, esto es, los
comentarios de una línea empiezan con
//, van hasta el final de la línea y no son procesados en el CSS de salida (son llamados
silent comments por este motivo).
Los
comentarios multi-línea empiezan con
/* y terminan con
*/. Por defecto, el comentario aparecerá en CSS, salvo en el caso de que éste sea comprimido. Por eso se llaman
loud comments.
Si el comentario empieza con
/*! aparecerá incluso si está comprimido.
Además, si el comentario está en un lugar donde podría ir una sentencia (expresión a evaluar) o contiene interpolación (resultado de una expresión SassScript), siempre aparecerá:
SCSS
// Este comentario no aparecerá en CSS.
/* Este comentario sí, salvo que el CSS esté comprimido. */
/* Puede contener interpolación:
* 1 + 1 = #{1 + 1} */
/*! Este comentario siempre aparecerá. */
p /* Los comentarios en línea pueden ir en cualquier lugar
* donde esté permitido un espacio en blanco. */ .sans {
font: Helvetica, // Al igual que los comentarios de una línea.
sans-serif;
}
CSS
/* Este comentario sí, salvo que el CSS esté comprimido. */
/* Puede contener interpolación:
* 1 + 1 = #{1 + 1} */
/*! Este comentario siempre aparecerá. */
p .sans {
font: Helvetica, sans-serif;
}
Los comentarios en
Sass funcionan de forma diferente, ya que están basados en la indentación, al igual que el resto de la sintaxis.
En el caso de los
comentarios de una línea, al igual que en SCSS, tampoco aparecerán en CSS, pero por el contrario todo lo que esté indentado, aunque sea en otras líneas, también pertenecerá un comentario.
Los
comentarios multi-línea funcionarán igual que antes, pero por el mismo motivo, es opcional cerrarlos con
*/.
Sass
// Este comentario no aparecerá en CSS.
Esto también estará comentado.
/* Este comentario sí, salvo que el CSS esté comprimido.
/* Puede contener interpolación:
1 + 1 = #{1 + 1}
/*! Este comentario siempre aparecerá.
p .sans
font: Helvetica, /* Los comentarios en línea siempre se deben cerrar. */ sans-serif
CSS
/* Este comentario sí, salvo que el CSS esté comprimido. */
/* Puede contener interpolación:
* 1 + 1 = #{1 + 1} */
/*! Este comentario siempre aparecerá. */
p .sans {
font: Helvetica, sans-serif;
}
Selectores placeholder
Existe un tipo de selector específico en Sass y SCSS llamado placeholder, que parece y actúa como un selector de clase estándar pero empieza con % y no se incluirá luego en el CSS de salida:
SCSS
.alert:hover, %strong-alert {
font-weight: bold;
}
%strong-alert:hover {
color: red;
}
Sass
.alert:hover, %strong-alert
font-weight: bold
%strong-alert:hover
color: red
CSS
.alert:hover {
font-weight: bold;
}
La pregunta es obvia:
¿Para qué queremos un selector que luego no aparece en el CSS de salida?
Básicamente
porque aún lo podemos extender. Todavía no hemos hablado de la directiva
@extend, pero básicamente nos permitirá extender cualquier estilo (heredar de él, vaya).
De este modo, estos
placeholder selectors nos permitirían crear una plantilla de estilos que podríamos extender en un momento dado (como una librería en un archivo aparte) y sólo aparecerán en el CSS de salida si los hemos utilizado:
SCSS
%toolbelt {
box-sizing: border-box;
border-top: 1px rgba(#000, .12) solid;
padding: 16px 0;
width: 100%;
&:hover { border: 2px rgba(#000, .5) solid; }
}
.action-buttons {
@extend %toolbelt;
color: #4285f4;
}
.reset-buttons {
@extend %toolbelt;
color: #cddc39;
}
Sass
%toolbelt
box-sizing: border-box
border-top: 1px rgba(#000, .12) solid
padding: 16px 0
width: 100%
&:hover
border: 2px rgba(#000, .5) solid
.action-buttons
@extend %toolbelt
color: #4285f4
.reset-buttons
@extend %toolbelt
color: #cddc39
CSS
.action-buttons, .reset-buttons {
box-sizing: border-box;
border-top: 1px rgba(0, 0, 0, 0.12) solid;
padding: 16px 0;
width: 100%;
}
.action-buttons:hover, .reset-buttons:hover {
border: 2px rgba(0, 0, 0, 0.5) solid;
}
.action-buttons {
color: #4285f4;
}
.reset-buttons {
color: #cddc39;
}
Funciones especiales
CSS define muchas funciones y la mayoría de ellas funcionan perfectamente con la sintaxis de Sass/SCSS, analizadas como llamadas a funciones, resueltas como funciones de CSS y compiladas como tal en CSS.
Sin embargo, hay algunas excepciones con una sintaxis especial que no pueden ser analizadas como expresiones
SassScript.
La función
url() en CSS permite que el uso de comillas en el string de la url sea opcional, pero no usar comillas sería una expresión
SassScript válida, con lo que hay que utilizarla con cuidado si tiene variables:
SCSS
$roboto-font-path: "../fonts/roboto";
@font-face {
// Será analizada como una función normal que lleva un string entre comillas.
src: url("#{$roboto-font-path}/Roboto-Thin.woff2") format("woff2");
font-family: "Roboto";
font-weight: 100;
}
@font-face {
// Será analizada como una función normal que lleva una expresión aritmética
src: url($roboto-font-path + "/Roboto-Light.woff2") format("woff2");
font-family: "Roboto";
font-weight: 300;
}
@font-face {
// Será analizada como una función especial interpolada.
src: url(#{$roboto-font-path}/Roboto-Regular.woff2) format("woff2");
font-family: "Roboto";
font-weight: 400;
}
Sass
$roboto-font-path: "../fonts/roboto"
@font-face
// Será analizada como una función normal que lleva un string entre comillas.
src: url("#{$roboto-font-path}/Roboto-Thin.woff2") format("woff2")
font-family: "Roboto"
font-weight: 100
@font-face
// Será analizada como una función normal que lleva una expresión aritmética
src: url($roboto-font-path + "/Roboto-Light.woff2") format("woff2")
font-family: "Roboto"
font-weight: 300
@font-face
// Será analizada como una función especial interpolada.
src: url(#{$roboto-font-path}/Roboto-Regular.woff2) format("woff2")
font-family: "Roboto"
font-weight: 400
CSS
@font-face {
src: url("../fonts/roboto/Roboto-Thin.woff2") format("woff2");
font-family: "Roboto";
font-weight: 100;
}
@font-face {
src: url("../fonts/roboto/Roboto-Light.woff2") format("woff2");
font-family: "Roboto";
font-weight: 300;
}
@font-face {
src: url(../fonts/roboto/Roboto-Regular.woff2) format("woff2");
font-family: "Roboto";
font-weight: 400;
}
La función
calc(), al contener una expresión matemática, puede generar conflicto con la aritmética de Sass, mientras que la función
element() puede hacer que los IDs sean analizados como colores. En ambos casos necesitaremos una sintaxis especial mediante interpolado:
SCSS
.logo {
$width: 800px;
width: $width;
position: absolute;
left: calc(50% - #{$width / 2});
top: 0;
}
Sass
.logo
$width: 800px
width: $width
position: absolute
left: calc(50% - #{$width / 2})
top: 0
CSS
.logo {
width: 800px;
position: absolute;
left: calc(50% - 400px);
top: 0;
}
Nota:
element(id) es una función de CSS que define una imagen creada anteriormente, útil en entornos que usan
canvas, pero solo es compatible en Firefox.
Las funciones
min() y
max(), recientemente incorporadas a CSS, podrían generar conflicto con las funciones Sass más antiguas y del mismo nombre, con lo que de nuevo es necesario utilizar una sintaxis especial con interpolación:
SCSS
$padding: 12px;
.post {
// Como esta llamada a max() solo una interpolación, será analizada como la función max() de css.
padding-left: max(#{$padding}, env(safe-area-inset-left));
padding-right: max(#{$padding}, env(safe-area-inset-right));
}
.sidebar {
// Como esta llamada a max() incluye una variable de Sass, será analizada como la función max() de SassScript.
padding-left: max($padding, 20px);
padding-right: max($padding, 20px);
}
Sass
$padding: 12px
.post
// Como esta llamada a max() solo una interpolación, será analizada como la función max() de css.
padding-left: max(#{$padding}, env(safe-area-inset-left))
padding-right: max(#{$padding}, env(safe-area-inset-right))
.sidebar
// Como esta llamada a max() incluye una variable de Sass, será analizada como la función max() de SassScript.
padding-left: max($padding, 20px)
padding-right: max($padding, 20px)
CSS
.post {
padding-left: max(12px, env(safe-area-inset-left));
padding-right: max(12px, env(safe-area-inset-right));
}
.sidebar {
padding-left: 20px;
padding-right: 20px;
}
Nota:
env() es una función de CSS que permite llamar a una variable de entorno previamente definida, pero solo es compatible en algunos navegadores.
Referencias