Variables CSS

Inauguramos la nueva temporada del blog con un post sobre una de las características de CSS más nuevas (lleva algunos años con nosotros, pero no tantos siendo soportada por los navegadores) y menos aprovechadas: las variables CSS, también conocidas como Custom Properties.

Los que empezamos en esto de las webs por el backend, es decir, programando más que maquetando, recibimos con los brazos abiertos cualquier avance en el mundo del frontend que se dirija a asumir técnicas ya asentadas en el mundo de la programación. Sin variables sería imposible programar, y es una característica que echamos mucho de menos al meternos en el desarrollo HTML/CSS.

Por ejemplo, si tenemos una cabecera fija (sticky, para los más molones), con una línea de texto centrada verticalmente, y queremos que el contenido de nuestra web empiece por debajo de ella, tendremos que hacer algo así:


.header.sticky {
     height: 100px;
     line-height: 100px;
 }

 body {
     padding-top: 100px;
}

Si eres programador y has tenido que escribir esto, te habrán rechinado los dientes al tener que repetir tres veces el valor de la altura. Lo normal en un lenguaje de programación es que ese 100px esté almacenado en una variable. Pero esto no es un lenguaje de programación, es CSS. Con lo cual, el día que queráis cambiar la altura de la cabecera, tendréis que cambiarlo en tres sitios diferentes. Esto hace que nuestra web sea un poco más difícil de mantener, al no respetar el principio DRY.

Es cierto que en este ejemplo tampoco supondría mucho trabajo cambiarlo en los tres sitios (por no decir que para centrar el texto verticalmente nos podemos ahorrar ese line-height, pero no me fastidiéis el ejemplo), pero la realidad siempre es más compleja. Lo más normal es que el CSS esté repartido en varios archivos, y si queremos que nuestra web sea escalable, es decir, que se pueda ampliar sin dificultad, hay que contar con que otros desarrolladores podrán necesitar tirar de ese valor de 100px en más sitios. Entonces, ¿no sería mucho mejor tener el 100px almacenado en un único lugar, y que todas las propiedades CSS que lo necesitaran fueran a buscarlo a ese lugar? Así, si necesitamos cambiar el 100px por un 120px, sólo tendríamos que ir a ese lugar y modificar el valor. Todas las propiedades que fueran a buscarlo ahí se llevarían el nuevo valor. Y eso es justamente lo que nos permite una variable.

La llegada de los preprocesadores CSS

Cuanto más potente se ha ido haciendo CSS, más se han ido echado de menos algunas características de los lenguajes de programación. Afortunadamente, en esa evolución aparecieron Sass, Less y Stylus, los llamados preprocesadores CSS, con la intención de proveernos de herramientas o técnicas de desarrollo más parecidas a las de la programación.

Todo el que haya usado un preprocesador CSS se habrá aprovechado de al menos dos de sus características, las primeras que se aprenden: las anidaciones y las variables. Hablemos de las segundas, que son las que nos interesan en este post. En los ejemplos usaré la sintaxis de SASS, por ser el más usado, pero el funcionamiento es aplicable a los tres.

Si trasladamos el ejemplo anterior a SASS, haríamos algo así:


.header.sticky {
    height: $header-height;
    line-height: $header-height;
}

body {
    padding-top: $header-height;
}

Al compilar este código, el CSS resultante será idéntico al que escribíamos más arriba. Sin embargo, sólo hemos tenido que escribir el valor 100px una vez. Y no sólo eso, si mañana queremos modificar la altura a 120px, sólo tendremos que tocar en una línea:


$header-height: 120px;

De este modo, no nos tenemos que preocupar de los tres lugares donde se utiliza ese valor, y tampoco nos preocuparemos de si el día de mañana en vez de tres son diez los lugares donde se utiliza ese 120px.

Os pongo un ejemplo un poco más complejo, y bastante cotidiano: una web maquetada con Bootstrap. El framework trae sus medidas y colores ya establecidos, y lo más lógico es que queráis adaptarlos a vuestro diseño. Si nos descargamos la versión no compilada (en Less o en Sass), veremos que trae un archivo de variables, del que ponemos aquí un fragmento:


// Start with assigning color names to specific hex values.
$white: #fff !default;
$black: #000 !default;
$red: #d9534f !default;
$orange: #f0ad4e !default;
$yellow: #ffd500 !default;
$green: #5cb85c !default;
$blue: #0275d8 !default;
$teal: #5bc0de !default;
$pink: #ff5b77 !default;
$purple: #613d7c !default;

...

// Reassign color vars to semantic color scheme
$brand-primary: $blue !default;
$brand-success: $green !default;
$brand-info: $teal !default;
$brand-warning: $orange !default;
$brand-danger: $red !default;
$brand-inverse: $gray-dark !default;

Así, si nosotros queremos que el color corporativo de nuestra web sea el #ff7f00, sólo tendremos que establecer el valor de la variable desde nuestra hoja de estilos:


$brand-primary: #ff7f00;

De este modo, todos los elementos de Bootstrap que usen el color corporativo cogerán el valor que hemos establecido nosotros, y no el que traía el framework por defecto (cada preprocesador tiene su metodología para establecer valores por defecto que puedan ser sobreescritos por el usuario).

¿Y el CSS?

Pero aquí habíamos venido a hablar de variables en CSS. Así que vamos a ello.

Mientras todos dábamos por supuesto que la única manera de usar variables en CSS eran los preprocesadores, silenciosamente se iba abriendo paso una especificación de CSS que hablaba de variables o custom properties. Podemos decir que a día de hoy es una característica ampliamente soportada por los navegadores (en el momento de redactar este post aún sigue entre nosotros IE11, que no la soporta, pero que tiene un uso prácticamente residual).

Las variables en CSS se utilizan empleando esta sintaxis un poco engorrosa:


/* Declaramos la variable */
:root {
    --header-height: 100px;
}

/* Usamos la variable */
.header.sticky {
    height: var(--header-height);
    line-height: var(--header-height);
}
body {
    padding-top: var(--header-height);
}

Como vemos, las variables se declaran siempre bajo un elemento. En este caso usamos la pseudoclase :root, que en un documento HTML se refiere al elemento <html>. El nombre de la variable siempre llevará el prefijo --, y para usar la variable tendremos que usar var(--nombre-variable).  Haciendo esto volvemos a tener el valor en un único lugar, y es en ese único lugar donde tendremos que cambiarlo si dentro de un mes la cabecera cambia de altura.

¿Son mejores o peores que las variables de los preprocesadores?

Difícil pregunta. La esquivaremos con el viejo truco de listar ventajas e inconvenientes (es decir, decide tú).

Ventajas

La principal ventaja es que es una característica nativa de CSS. No necesitas nada para que el navegador la entienda. Los preprocesadores tienen que compilar primero a CSS, para que el navegador pueda entender el código. Esto difícilmente te va a ahorrar tener que usar preprocesadores, pero ya es algo.

A causa de lo explicado en el anterior punto, una vez que el código compilado llega al navegador, esos valores ya no se pueden cambiar, se quedan fijos hasta la próxima recarga. Sin embargo, las variables nativas de CSS pueden ser modificadas en cualquier momento. Por ejemplo, si yo modifico el valor de una variable dentro de una media query y cambio el tamaño del navegador, puedo ver cómo el valor cambia al vuelo.


:root {
    --header-height: 100px;
}

.header.sticky {
    height: var(--header-height);
    line-height: var(--header-height);
}
body {
    padding-top: var(--header-height);
}
@media (max-width: 768px) {
    :root {
        --header-height: 200px;
    }
}

Con este código estamos modificando tres propiedades de dos elementos diferentes, usando sólo una media query.

Otra ventaja es que los valores se heredan en cascada. Es decir, si yo defino una variable con un valor en el elemento :root, todos los elementos descendientes que la usen heredarán ese valor. Pero si en uno de los elementos modifico su valor, ese nuevo valor será visible sólo para los descendientes de este elemento, y no para el resto. Para verlo más claro:


:root {
    --text-color: blue;
}

.main-content {
    --text-color: grey;
}
.header {
    color: var(--text-color); /* Será blue */
}
.main-content .title {
    color: var(--text-color); /* Será grey */
}

Desventajas

Una de las desventajas más claras es tener que acostumbrarse a una sintaxis algo extraña e incómoda, sobre todo si también eres programador. Hasta que te hagas con ella, te encontrarás decenas de veces con el error de haber escrito directamente el nombre de la variable olvidando el var().

Otra desventaja es que aún hay algunos navegadores que no tienen soporte para las variables. Si necesitas que tu web funcione en IE11, no podrás usarlas.

Conclusiones

Si bien su sintaxis y el extendido uso de preprocesadores harán probablemente que las vayamos adoptando muy poco a poco, parece que las variables son un gran avance para conseguir un CSS nativo más escalable y reutilizable.

¿Qué opinas?

Tu dirección de correo electrónico no será publicada. * Campos obligatorios