miércoles, 2 de noviembre de 2022

👨‍💻 Variables CSS

Quizás lo desconozcas, ya que es una característica moderna que no estaba presente en las primeras versiones de CSS, pero es importante que sepas que existe una forma nativa de guardar valores a través de lo que se conoce como «variables CSS» . Estas variables CSS no existían hace años, y de hecho, fue una de las razones por las que se popularizaron preprocesadores como LESS o Sass, que sí las incorporaban.

CSS Custom Properties - Variables CSS

Sin embargo, las denominadas «variables CSS» realmente no son variables, sino que solemos denominarlas así por su parecido con la programación y porque es más fácil comprender rápidamente lo que son, pero tienen sus diferencias.

La forma oficial de llamarlas es «custom properties» (propiedades personalizadas).

CSS Custom Properties

Las «CSS custom properties»   (muchas veces conocidas por variables CSS) son un mecanismo de CSS que permite dar un valor personalizado a las propiedades. El objetivo principal suele ser evitar escribir múltiples veces ese valor, y en su lugar, ponerle un nombre más lógico y fácil de recordar, que hará referencia al valor real.

De esta forma, si necesitamos cambiar el valor en algún momento, podemos hacerlo en esa propiedad personalizada y no en múltiples partes del documento, donde nos podríamos equivocar al añadir el mismo valor o incluso hacer mucho más difícil de mantener el código.

Las «variables CSS»   o custom properties nos permiten simplificar la creación y sobre todo el mantenimiento y la reutilización de archivos CSS porque con las variables CSS podemos definir en un solo sitio los valores que de otro modo reutilizaríamos en múltiples sitios como los colores, fuentes, etc. que se suelen reutilizar en múltiples elementos y que sin la ayuda de las variables se hacía complicado de mantener ya que la única forma de hacer un cambio era buscar todas las apariciones de ese color por ejemplo y sustituirlo con la consiguiente posibilidad de cometer errores porque por ejemplo un color cómo #12df34 obviamente no te dice nada y puede ser complicado saber si es el color que estas cambiando o es una «casualidad» que sea el mismo.

Con los preprocesadores como SASS, LESS, etc. ya teníamos la posibilidad de utilizar variables pero la diferencia es que al estar soportadas nativamente en el propio CSS (y soportadas por todos los navegadores actuales desde hace un tiempo) se pueden modificar dinámicamente mediante javaScript por lo que tenemos un punto más de control sobre nuestros estilos CSS.

¿Como se definen las variables CSS?

Para definir una custom property (o variable) hay que poner como prefijo del nombre de la variable dos guiones -- previos al nombre que queramos utilizar. Además, debemos fijarnos en el elemento que definimos la variable, en este ejemplo la pseudoclase :root:

Hay varios detalles que comentar sobre este fragmento de código:

En primer lugar, la pseudoclase :root hace referencia al elemento raíz del documento, o lo que es lo mismo, al elemento <html>.

La diferencia de utilizar <html>   o :root como selector es que este último tiene algo más de especificidad CSS. Mientras que <html> tiene 001:root tendría 010.

Al colocarla en :root estamos definiendo que la custom property estará definida para el ámbito de esa etiqueta <html> (o cualquier elemento hijo), es decir, a todo el documento. Sin embargo, ya veremos que podemos aplicar estas variables sólo a partes concretas del DOM de nuestra página.

Nota: Las custom properties se suelen agrupar en las primeras líneas de un bloque CSS, separándolas por un espacio de otras propiedades estándar. Esto facilita la lectura del código.

Las variables siempre se tienen que declarar dentro de un selector CSS y son accesibles desde todos los selectores descendientes en el DOM, por eso normalmente las variables se suelen declarar usando el pseudoelemento :root que es equivalente a la etiqueta <html> para que se puedan usar de forma global.

Una cosa importante a tener en cuenta en cuanto a la definición es que no importa el orden en el que se haga la declaración y el uso de la variable porque no estamos en un lenguaje de programación como tal y por lo tanto no hay un flujo de ejecución por lo tanto sería perfectamente posible definir las variables al final de nuestros estilos.

¿Como se usan las variables CSS?

Al momento de utilizar una variable, hay que utilizarla dentro de la expresión var(--nombre-variable).

En este caso estamos aplicando a la propiedad color el valor que contiene --color-texto para el elemento mi-clase. Esto último es muy importante entenderlo, ya que una variable puede tener diferentes valores dependiendo del ámbito en el que se encuentra.

Además, es muy recomendable que la función var() opcionalmente tenga dos parámetros:

  • El primero de ellos, la variable en cuestión,
  • el segundo de ellos, para indicar el valor por defecto que debe de tomar esa propiedad, en el caso de que la primera variable no este definida dentro del elemento en el que se está utilizando.

Por ejemplo para que el color del texto sea azul cuando no se encuentre la variable --color-texto lo haríamos así.

En nuestro caso, el elemento con clase .mi-clase tendrá siempre el color de fondo negro, pero podría adoptar el color azul si la custom property no se hubiera declarado.

El valor por defecto no tiene por qué ser un valor fijo, se puede utilizar otra variable en su lugar para hacer definiciones de estilos más complejas en las que por ejemplo tengamos unos valores predefinidos de forma global pero queramos que si el elemento está dentro de una jerarquía determinada use los valores de está, y por supuesto nada impide que la variable que usamos como valor por defecto tenga a su vez otra variable por defecto.

Herencia de variables CSS

Aunque las llamemos variables, en realidad son unas variables un poco raras porque las «variables» CSS se heredan en los elementos hijos del elemento en el que se definen, y dentro de estos pueden redefinirse pero los cambios no afectan a la definición en el padre, por este motivo quizás les encaje mejor en nombre de propiedades personalizadas.

Vamos a verlo con un ejemplo sencillo en que tenemos un elemento padre que tiene dentro un elemento hijo y este a su vez tiene dentro otro elemento nieto.

En este caso definimos la variable --color-fondo a nivel global, después la volvemos a redefinir en el padre y en el hijo por lo tanto esta variable tiene 3 valores distintos dependiendo de donde la utilicemos. Si la usamos en el padre el color es #147, en el hijo o en el nieto el color es #741 y si la usamos en cualquier elemento que no esté dentro del padre, el hijo o el nieto el color será rgb(29,30,34).

En este pequeño ejemplo he incluido una variable que a su vez tiene dentro otra variable para definir una propiedad con múltiples valores como el borde, esto es perfectamente válido porque nada nos impide llamar a una variable dentro de otra variable pero hay una limitación muy importante y es que en CSS no existe la posibilidad de concatenar valores y por lo tanto no podemos hacer que por ejemplo el 1 fuese una propiedad y que los px fuesen otra porque no se pueden unir.

¿Cómo acceder y modificar las variables CSS con javaScript?

Una de las cosas más interesantes que aportan las variables CSS es que se pueden editar desde el código javaScript y por lo tanto se pueden cambiar dinámicamente de forma que es posible cambiar el aspecto de varios elementos simultáneamente sin tener que tener definidas clases específicas y tener que cambiarlas una a una. Un ejemplo muy claro y muy sencillo es pensar en lo sencillo que es definir un tema usando variables para sus colores y lo simple que sería cambiar la apariencia simplemente permitiendo que el usuario los pusiese cambiar como quiera mientras puede ver sus cambios en tiempo real y además sin tener que definir ninguna clase para cada posible tema se consigue que sea 100% personalizable, aunque como con todas las cosas hay que ver cuando realmente es útil y cuando se está abusando de forma incorrecta, por ejemplo cambiar una variable desde javaScript para cambie el color al pasar por encima de un elemento es una completa estupidez, para eso esta el CSS.

La forma de acceder a una variable CSS desde javaScript es utilizando las funciones getComputedStyle() para obtener los estilos del elemento y getPropertyValue() para acceder a la propiedad concreta.

Para poder modificar su valor necesitamos utilizar la función setProperty() sobre la propiedad style del elemento sobre el que lo queremos hacer.

Como puedes ver en el primer ejemplo podemos darle el nuevo valor que queramos a la variable, incluida la posibilidad de usar otras variables CSS, porque al fin y al cabo desde el punto de vista de la definición es simplemente una cadena de texto que se interpretará como corresponda en el CSS, y en la segunda función redefinimos una variable en un elemento en el que inicialmente no estaba definida aunque sí que era accesible porque está definida en su padre y además le damos el valor que tiene en el nivel superior para comprobar que de verdad al redefinir una variable en un elemento hijo el cambio en la variable no afecta al padre.

Te dejo este fiddle para que veas cómo funciona.

Variables CSS desde Javascript

Existen varias formas de manipular estilos CSS desde Javascript, ya sea directamente a través de la propiedad .style del elemento en cuestión, o utilizando la función global de cada página .getComputedStyle(), que devuelve los estilos computados por el navegador.

Sin embargo, en esta ocasión nos centraremos en una serie de métodos de ayuda que nos hacen la vida más fácil, ya que podemos establecer, obtener y/o eliminar propiedades CSS (custom properties incluídas) de un elemento de forma muy sencilla.

Observen el siguiente método mediante el cuál añadimos (o modificamos) la propiedad border de un elemento del DOM de nuestro HTML:

const element = document.querySelector(".element");
element.style.setProperty("border", "2px solid red");

Al igual que lo hacemos con una propiedad CSS, lo podríamos hacer con una custom property, la cuál quedaría añadida en el atributo HTML style del elemento.

Los métodos de ayuda que tenemos para modificar propiedades son los siguientes:

Método Descripción
.setProperty(name,value,priority) Añade/cambia el valor de una propiedad CSS.
.getPropertyValue(name) Obtiene el valor de una propiedad CSS.
.getPropertyPriority(name) Devuelve important si tiene prioridad.
.removeProperty(name) Elimina una propiedad CSS de un elemento.

El método que hemos visto anteriormente es .style.setProperty(), con el cuál podemos añadir (o modificar) un valor a una propiedad. Además, si establecemos el tercer parámetro con el important, sería equivalente a añadirle el !important al valor de la propiedad.

Por otro lado, tenemos el método opuesto .style.getPropertyValue() mediante el cuál podemos obtener el valor de una propiedad concreta o el método .style.getPropertyPriority(), con el cuál te devuelve el string important si lo tiene definido. Por último, el método .style.removeProperty() como su propio nombre indica, elimina una propiedad de un elemento.

Nota: Ten en cuenta que estas propiedades solo funcionan si los estilos CSS o custom properties han sido definidas a través del atributo style de CSS o con estos mismos métodos (que lo hacen por la misma vía).

Soporte en los navegadores

Las variables tienen un buen soporte en navegadores en la actualidad, a excepción, como siempre, de Internet Explorer.

Si necesitaras soporte para IE11, quizás podría venirte bien el polyfill ie11CustomProperties.

Diferencia con Sass

También es importante mencionar que las variables CSS no funcionan exactamente igual que las variables Sass (o en general, las variables de preprocesadores).

Sass al igual que muchos otros preprocesadores de CSS, no trabajan directamente en el navegador, sino en una capa previa (capa de preprocesamiento). Por lo tanto, muchas tareas se realizan antes de llegar al navegador.

Es el caso de las variables de Sass, dichas variables son leídas por Sass y convertidas a CSS «plano» (sin variables):

Un segundo ejemplo

Para finalizar, amos analizar otro ejemplo aún más específico, para afianzar la lección.

Observa el marcado HTML del siguiente ejemplo, donde tenemos tres elementos con clase child, los dos primeros dentro de parent y el tercero fuera:

Sin embargo, ahora estamos definiendo la variable --background-color en diferentes ámbitos:

  • Los dos primeros elementos .child tomarán color negro, ya que se le aplica a .parent (e hijos).
  • El primer elemento .child se sobreescribe con color púrpura, ya que se le aplica a .first.
  • El tercer elemento no tendrá ninguna variable definida, por lo que tomará color azul.

Esto nos permite mucha flexibilidad y potencia a la hora de utilizar custom properties en CSS, ya que son tremendamente útiles y versátiles, permitiéndonos utilizar incluso la cascada de CSS a nuestro favor.

Te dejo este fiddle con el segundo ejemplo, para fundamentar más, cómo funciona el procedimiento explicado.