Desarrollo móvil multiplataforma
 

[Tutorial Sass] II – Anidación, Variables, Funciones e Importación

[Tutorial Sass] II – Anidación, Variables, Funciones e Importación

 

Tras ver cómo instalar Sass y cómo configurar nuestro entorno de trabajo, ha llegado el momento de analizar en profundidad qué funcionalidades nos ofrece y descubrir la potencia que esconde este preprocesador CSS. En este artículo analizaremos la sintaxis del metalenguaje y comprobaremos cómo podremos generar hojas de estilo más ricas a nivel semántico y mucho más eficientes.

Anidación (nesting)

La principal caraterística de Sass es poder definir reglas de maquetación de forma anidada, evitando que tengamos que repetir constantemente los prefijos de alcance en los selectores CSS.

Como ya sabrás, uno de los problemas de los selectores CSS es que  cuanto más específicos sean estos, más tendremos que repetir una y otra vez la cadena de elementos que conforman el selector, y según queramos añadir bloques a elementos inferiores tendremos que repetir cada vez la cadena de selección, como se puede ver en el siguiente ejemplo:

#content            { border: 1px solid black; }
#content p.info     { color: #fff; }
#content p.info a   { text-decoration: none; }

Como se puede observar, tenemos que ir repitiendo los elementos base del selector según vamos estilizando los elementos más internos. Esto tiene 3 principales problemas:

  1. El documento CSS se hace poco legible
  2. Tenemos que hacer un uso excesivo de elementos repetitivos y por consiguiente copy/paste, lo cual induce a errores
  3. A la larga tendemos a ser mas vagos y por pereza vamos haciendo selectores más pobres para “ahorrar tecla”

Sass evita estos incovenientes ofreciéndonos la posibilidad de anidar unos selectores dentro de otros. Veamos cómo se escribiría el ejemplo anterior en Sass:

#content {
  border: 1px solid black;
  p.info {
    color: #fff;
    a { text-decoration:none;}
  }
}

Como podemos ver, no tendremos que repetir las cadenas de selección completas pues Sass se encargará de introducirlas cuando lo compilemos a CSS, con lo cual no solo ganamos en limpieza, sino que el documento queda estructurado de una forma más natural, pues el anidamiento de selectores está más alineado con el anidamiento real que esperamos encontrar en el documento HTML que estamos estilizando.

Sass quiere evitar repitamos elementos en nuestro maquetación CSS. Por ese motivo, además de anidar selectores también podremos anidar propiedades de forma que no tengamos que repetir constantemente cosas como “border-left”. Podemos verlo en este ejemplo:

/* SCSS */
.bordemolon {
  border: {
    style: solid;
    left: {
      width: 4px;
      color: #888;
    }
    right: {
      width: 2px;
      color: #ccc;
    }
  }

/* CSS generado */
.bordemolon {
  border-style: solid;
  border-left-width: 4px;
  border-left-color: #888;
  border-right-width: 2px;
  border-right-color: #ccc; }

Aunque en estos ejemplos hemos anidado visualmente los elementos en los ficheros fuente, esto no es obligatorio en la sintaxis SCS (en la sintaxis Original Sass sí), pero ya que son ficheros fuente que luego compilaremos, es recomendable realizar el tabulado visual para mejorar la legibilidad.

Uso de referencias en anidaciones

Sass también soporta el concepto de “hijo directo” que podemos representar en CSS con el símbolo >. En el siguiente ejemplo se puede ver cómo podemos hacer uso de este operador:

/* SCSS */
.blog > {
  .post {
    width: 800px;
    > .title{
      font-weight: bold;
    }
  }
  .comments{
    margin-left: 20px;http://test.alfonsomarin.com/wp/movil/-/tutorial-sass-ii-sintaxis-basica/
  }
}

/* CSS generado */
.blog > .post {
  width: 800px;
}
.blog > .post > .title {
  font-weight: bold;
}
.blog > .comments {
  margin-left: 20px;
}

Uso de referencias en anidación

Al compilar nuestro código a SCSS a CSS, Sass prefijará por norma general cualquier selector anidado con la concatenación de sus selectores padre, siempre concatenándolos con espacios como se puede ver en este ejemplo:

/* SCSS */
.blog {
  .post p{
    em{
      color: #fff;
    }
  }
}

/* CSS generado */
.blog .post p em {
  border: color: #fff;
}

Esta es la regla general, pero un selector anidado puede indicar exactamente cómo quiere que se le añadan su selectores padre gracias al operador &, el cual representa precisamente a su selector padre. El símbolo & lo podemos poner en cualquier posición de nuestro selector, y si no lo ponemos es como si realmente lo pusiésemos al principio y seguido de un espacio, es decir, el comportamiento por defecto: ponme mi selector padre delante de mí separado por un espacio. Para que quede mas claro, estas dos versiones del ejemplo anterior serían equivalentes:

A continuación se muestran unos ejemplos donde indicamos que se añadan los selectores padre en posiciones específicas. Merece especial atención el último ejemplo, pues gracias a esta técnica conseguimos definir selectores con pseudoclases tipo “:hover” gracias a que eliminamos el espacio de concatenación por defecto.

/* Insertar .blog entre .post y p */
.blog {
  .post & p {
    em {
    	color: #fff;
    }
  }
}
 
/* Insertar al final */
.blog {
  .post p {
    em & {
    	color: #fff;
    }
  }
}
 
/* Pseudoclase :hover en p */
.blog {
  .post p {
    &:hover em {
    	color: #fff;
    }
  }
}

/* CSS Generado */
/* Insertar .blog entre .post y p */
.post .blog p em {
  color: #fff;
}
 
/* Insertar al final */
em .blog .post p {
  color: #fff;
}
 
/* Pseudoclase :hover en p */
.blog .post p:hover em {
  color: #fff;
}

Variables

Una de las principales carencias de CSS es la imposibilidad de definir variables, teniendo que especificar una y otra vez aquellos valores que queramos aplicar de forma general a varios elementos. Un caso típico suelen ser el conjunto de colores base del tema que estamos maquetando.

Sass introduce la posibilidad de definir variables, donde las especificaremos prefijándoles el símbolo $. Estas variables se comportan como atributos CSS, y su valor puede ser cualquier valor que pudiera adquirir cualquier atributo CSS. Veamos unos ejemplos:

$color_link: blue;
$default_border: 1px solid black;
$std_margin: 5px;
a {
  color: $color_link;
  border: $default_border;
  margin: $std_margin 0px $std_margin 0px;
}

/* CSS Generado */
a {
  color: blue;
  border: 1px solid black;
  margin: 5px 0px 5px 0px;
}

Una variable se podrá definir fuera o dentro de algún selector. Si se define fuera, dicha variable será global y podrá utilizarse en cualquier bloque, pero si se define dentro de un selector, la variable será local y únicamente se podrá utilizar en el selector que la contiene y en sus selectores anidados.
A continuación se muestra un ejemplo se muestra el uso de una variable global ($color_link) y una variable local ($var_local). En el propio ejemplo se muestra una asignación comentada que provocaría un fallo de compilación al intentar asignar una variable local fuera de su alcance.

$color_link: blue;
p{
  a {
    color: $color_link;
    $var_local: white;
    &.link{
      color: $var_local;
    }
}
 /* color: $var_local;

/* CSS Generado */
p a {
  color: blue;
}
p a.link {
  color: white;
}

Una buena práctica común consiste en definir todas las variables globales al principio del fichero, para que puedan localizarse rápidamente. Incluso en proyectos de gran envergadura, es común extraer todas las variables globales en un fichero exclusivo.

A la hora de definir una variable, podemos hacer uso de la directiva !default al final de la misma. Esta directiva indicará que la asignación que estamos realizando a la variable solo se haga en caso de que dicha variable no se haya definido anteriormente. Esta funcionalidad es especialmente interesante utilizarla en bloques de código Sass que queramos reutilizar, pues si todas las variables implicadas incluyen esta directiva permitiremos que se puedan personalizar sus valores sin necesidad de modificar el código en sí.

Operaciones aritméticas

Otra funcionalidad que nos ofrece Sass es poder realizar operaciones aritméticas sobre los valores de las propiedades. Por ejemplo, podríamos hacer width: 500px * 0.5, de forma que se calcularía sass calcularía 250px para la propiedad width. Podemos utilizar los 4 operadores aritméticos +, -, * y / (suma, resta, multiplicación y división), y Sass siempre respetará las unidades de las propiedades (px, em, etc…), salvo que éstas entren en conflicto, como por ejemplo si intentamos multiplicar una cantidad especificada en ‘px’ con otra especificada en ’em’.

Las operaciones aritméticas son realmente interesantes si las combinamos con las variables explicadas en el punto anterior, pues nos permiten estructurar el layout de nuestro proyecto en base a un conjunto de valores fijos, de forma que si estos cambian, todo seguirá estando bien definido de forma proporcional. Veamos un ejemplo de esto: supongamos que queremos crear un menú horizontal de ancho fijo en el que todos los botones tengan el mismo ancho:

$width-menu: 500px;
$num-botones: 10;
 
.menu {
  width: $width-menu;
  .boton{
    width: $width-menu / $num-botones;
  }
}

/* CSS Generado */
.menu {
  width: 500px;
}
.menu .boton {
  width: 50px;
}

Como podrás imaginar, lo interesante del ejemplo anterior es que si cambia el ancho del menú o el número de botones, solo tendremos que modificar el valor de las variables y todo el layout se recalculará automáticamente.

Funciones

Además de usar operaciones aritméticas para calcular valores de propiedades, también podremos hacerlo utilizando distintas funciones que Sass nos proporciona. El listado completo de funciones podemos encontrarlo en la guía de referencia de Sass.

Entre todas las funciones ofrecidas por Sass, las más utilizadas son las relacionadas con operaciones sobre colores. Por ejemplo, podríamos aclarar un color dado (lighten), oscurecerlo (darken), saturarlo (saturate), etc. También existen funciones para tratar con valores numéricos (abs, max, min, …) o con cadenas (length, join, …)

Vamos a ver un ejemplo de cómo se utiliza este tipo de funciones:

$btn-bg-color: #ce4dd6;
.menu {
  .button {
    background-color: $btn-bg-color;
    &:hover{
      background-color: lighten($btn-bg-color, 20%);
    }
    &:active{
      background-color: darken($btn-bg-color, 20%);
    }
    &.disabled{
      background-color: grayscale($btn-bg-color);
    }
  }
}

/*CSS Generado*/
.menu .button {
  background-color: #ce4dd6;
}
.menu .button:hover {
  background-color: #e5a0e9;
}
.menu .button:active {
  background-color: #93239a;
}
.menu .button.disabled {
  background-color: #929292;
}

@import

Como desarrolladores web sabemos que lo ideal es tener todas nuestras reglas CSS en un único fichero para así no penalizar la carga de nuestras páginas, pero por otra parte nos gustaría desglosarlo en distintos ficheros agrupando aquellas reglas que semánticamente estén relacionadas, y así evitar tener que lidiar con un único fichero CSS gigantesco.

Una vez más Sass nos facilita la vida ofreciéndonos lo mejor de ambos mundos. Por una parte, podremos desglosar las reglas de nuestro proyecto en tantos ficheros como deseemos, y luego indicarle a Sass que compile dichos ficheros por separado o todos en un único fichero CSS.

La instrucción que nos permitirá hacer esto es @import “fichero”, a la cual le indicaremos el nombre del fichero (sin la extensión) que queremos importar. Sass compilará el fichero que le hayamos indicado y lo insertará en el fichero original sustituyendo la línea del @import por el contenido compilado, como se puede ver en este ejemplo:

/* Contenido de fichero colors.scss */
$color: #aaa;
p {
  em{
    color: $color
  }
}
/* Contenido de fichero test.scss */
@import "colors";
 
p.test{
  em {
    color: $color;
  }
}

/* Contenido generado test.css */
/* line 4, ../scss/_colors.scss */
p em {
  color: #aaaaaa;
}
 
/* line 4, ../scss/test.scss */
p.test em {
  color: #aaaaaa

Aunque solo se muestra el contenido del fichero generado test.css, si estuviésemos monitorizando el directorio donde se encuentran estos ficheros .scss (usando Scout o el comando sass –watch, como vimos en el tema anterior) se generarían dos ficheros .css: test.css y colors.css. Si no queremos que se generen ficheros separados para un determinado fichero .scss que unicamente utilizarmos para importarlo en otros, como podría ser el caso de colors.scss, podremos renombrar el fichero e insertar un _ al principio. De esta forma, le estaremos indicando al compilador que no deseamos fichero .css de salida para dicha fuente, y semánticamente estamos indicando que ese fichero se utilizará únicamente para ser importado, no para generar código css por sí mismo. Por ese motivo, para diferenciarlos de los ficheros normales se les denomina partials.

Conclusión

En este tema hemos visto las primeras herramientas que nos proporciona Sass en su sintaxis y está claro lo mucho que nos pueden ayudar a la hora de crear nuestras hojas de estilo de una forma mucho más estructurada y eficiente. En el siguiente tema terminaremos de ver el resto de sus elementos.