Publicado originalmente en el blog de ingeniería de Toptal.
Si hace ya un tiempo que escribís hojas de estilo en cascada (CSS), en algún punto debés haber necesitado variables. Las propiedades personalizadas de CSS son algo así como la implementación de variables propia de CSS. Sin embargo, cuando se usan de forma adecuada, pueden ser mucho más que solo variables.
Las propiedades personalizadas de CSS te permiten:
➡ asignar valores arbitrarios a una propiedad con el nombre que elijas;
➡ usar la función var()
para reutilizar estos valores en otras propiedades.
A pesar de que el soporte para propiedades personalizadas de CSS sea un poco engorroso por ahora y que algunos navegadores las soporten con indicadores que deben activarse o establecerse como verdaderos de antemano, se espera que el soporte aumente significativamente a futuro, por lo que es importante entender cómo se usan y cómo aprovecharlas.
En este artículo aprenderás a usar las propiedades personalizadas de CSS para hacer que tus hojas de estilo sean un poco más dinámicas, lo cual podría dejar obsoleto al paso adicional de Sass/Less en tu canalización de activos.
Antes de ir a las propiedades personalizadas de CSS, debemos tener en cuenta que, desde hace bastante tiempo, CSS tiene un tipo de variable, la palabra clave currentColor
. Esta variable, rara vez usada, pero con un amplio soporte, se refiere al valor de color actual de un elemento. Puede usarse en cualquier declaración que admita un valor color
y se ubica en la cascada perfectamente.
Veamos un ejemplo:
.element { color: blue; border: 2px solid currentColor; /* Le agrega al elemento un borde azul sólido de 2 px de ancho */ }
Además, puede dar el siguiente resultado:
.element span { background: currentColor; /* Sets a blue background color for every span child of .element, unless a color property is declared in this same block */ } .element span.red { color: red; /* Sets a red background color for every span child of .element that has the class .red, since currentColor is applied to the background of every span child of .element no matter if they have the .red class or not */ }
El mayor problema de currentColor
, además de que no figurara en la especificación como una variable per se, es que solo admite el valor de la propiedad de color, lo que a veces puede dificultar el trabajo.
Una de las mayores ventajas de usar los pre- y postprocesadores CSS es que estos permiten almacenar los valores en una palabra clave y, de ser necesario, delimitar su alcance a un selector determinado.
Después de que los desarrolladores lo pidieran una y otra vez, se redactó un borrador sobre la interpretación de las variables nativas de CSS. Su denominación formal es “propiedades personalizadas de CSS”, aunque también se suelen llamar “variables CSS”.
La especificación actual de las propiedades personalizadas de CSS con funciones nativas abarca las mismas funcionalidades que las variables de pre- y postprocesador. Esto te permite almacenar códigos de colores, tamaños con todas las unidades conocidas o simplemente números enteros, de ser necesario, (p. ej., cuando tenés que usar el mismo divisor o multiplicador).
La sintaxis de las propiedades personalizadas de CSS es un poco rara en comparación con otros lenguajes, pero tiene mucho sentido si la comparás con otras herramientas dentro del mismo ecosistema de CSS:
:root { --color-black: #2e2e2e; } .element { background: var(--color-black); }
En este punto te debés estar preguntando: “¿qué tipo de sintaxis es esta?”.
En su increíble charla, titulada CSS Variables: var(–subtitle), Lea Verou explica en simples palabras la razón por la cual se usa esta sintaxis de dos guiones:
“Los guiones funcionan exactamente igual que cualquier otra propiedad de CSS [...]. Mucha gente me pregunta por qué no usamos un [signo de] dólar o algo así, y la razón por la cual no usamos un [signo de] dólar es porque queremos que la gente pueda usar tanto Sass, o variables de preprocesador, como variables CSS. Son dos cosas distintas; cumplen funciones distintas. Hay cosas que se pueden hacer con las variables CSS que de ninguna manera se pueden con Sass, y hay cosas que se pueden hacer con las variables Sass que no se pueden hacer con las variables CSS, así que queríamos que la gente pudiera usar ambas en la misma hoja de estilo. Pueden imaginarse la sintaxis de dos guiones como una propiedad de prefijo con un prefijo vacío.”
Podemos acceder al valor de la propiedad personalizada usando la función var()
, la cual se puede usar en cualquier lugar, excepto con selectores, nombres de propiedades o declaraciones de consulta de medios.
Vale la pena mencionar que las variables de pre- y postprocesador solo se usan al momento de hacer una compilación, mientras que las variables CSS se pueden usar y actualizar de forma dinámica. ¿Qué quiere decir esto? Quiere decir que se conservan en la hoja de estilo CSS real. Por lo tanto, la noción de que son variables se mantendrá incluso después de compilar las hojas de estilo.
Para que sea más claro, permítanme ilustrar la situación con algunos ejemplos. El siguiente bloque de código pertenece a una hoja de estilo Sass:
:root { $value: 30px; } @media screen and (min-width: 768px) { $value: 60px; } .corners { border-radius: $value; }
Este fragmento de declaraciones y reglas Sass se compila en CSS de esta manera:
.corners { border-radius: 30px; }
Notarán que las propiedades dentro de :root
y la consulta de media
se pierden tras la compilación. Esto se debe a que las variables Sass no pueden existir dentro de un archivo CSS (o, para ser más preciso, se puede hacer que existan dentro de un archivo CSS, pero se ignorarán debido a que parte de su sintaxis es CSS inválida); por lo tanto, el valor de la variable no se podrá actualizar más adelante.
Ahora tomemos el mismo caso, pero usando solo variables CSS sin aplicar pre- o postprocesadores CSS (es decir, sin hacer un transpilado o una compilación):
:root { --value: 30px; } @media screen and (min-width: 768px) { --value: 60px; } .corners { border-radius: var(--value); }
Obviamente, no hay ningún cambio porque no hemos transpilado ni compilado nada, y el valor de la propiedad personalizada puede actualizarse de forma dinámica. Así es que, por ejemplo, si cambiamos el valor de --value
usando un lenguaje como JavaScript, el valor se actualizará en cada caso en que se lo nombre con la función var().
Las funcionalidades de las propiedades personalizadas potencian tanto esta herramienta que incluso se pueden hacer cosas como agregar prefijos automáticamente.
Lea Verou da un ejemplo con la propiedad clip-path
. Empezamos estableciendo el valor de la propiedad que queremos agregar como prefijo de initial
, pero usamos una propiedad personalizada y luego proseguimos a establecer cada valor de la propiedad usada como prefijo en el valor de la propiedad personalizada:
* { --clip-path: initial; -webkit-clip-path: var(--clip-path); clip-path: var(--clip-path); }
Después, solo resta cambiar el valor de la propiedad personalizada dentro del selector:
header { --clip-path: polygon(0% 0%, 100% 0%, 100% calc(100% - 2.5em), 0% 100%); }
Si te interesa saber más sobre este tema, consultá el artículo de Lea sobre cómo establecer prefijos automáticamente con las variables CSS.
Como se ha mencionado, en la mayoría de los navegadores, el soporte para las propiedades personalizadas de CSS aún no es estándar. ¿Cómo se puede solucionar esto?
Acá es donde entran en juego PostCSS y su extensión, postcss-css-variables.
En caso de que te estés preguntando qué es PostCSS, consultá mi artículo titulado “PostCSS: SASS’s New Play Date” y retomá este una vez que lo hayas leído. Después de hacerlo, tendrás una idea básica sobre lo que podés hacer con esta herramienta increíble y no te sentirás desorientadx al leer el resto del artículo.
Con la extensión postcss-css-variables
y la opción preserve
establecida como verdadera, podemos conservar todas las declaraciones de la función var()
en la ventana de salida y tener el valor calculado como declaración de valor alternativo (fallback). Además, se mantienen las declaraciones de --var
calculadas. Recordá que, mediante esta extensión de PostCSS, las propiedades personalizadas se pueden actualizar de forma dinámica después del transpilado; sin embargo, los valores alternativos permanecerán iguales a menos que se identifiquen específicamente y se cambien uno a uno expresamente.
Si buscás usar las variables CSS sin recurrir a un pre- o postprocesador, siempre tenés la posibilidad de verificar el soporte actual manualmente con la regla CSS @support
y aplicar un valor alternativo adecuado cuando el soporte sea parcial o inexistente. Por ejemplo:
:root { --color-blue: #1e90ff; /* hex value for dodgerblue color */ }.element { background: var(--color-blue); }@supports (not(--value: 0)) { /* CSS variables not supported */ .element { background: dodgerblue; } }
A lo largo del artículo he afirmado que las variables pueden actualizarse usando JavaScript, así que vayamos a ese punto.
Imaginemos que tenés un tema claro y querés cambiarlo a uno oscuro y supongamos tenés una CSS como la siguiente:
:root { --text-color: black; --background-color: white; }
body { color: var(--text-color); background: var(--background-color); }
Podés actualizar las propiedades personalizadas --text-color
y --background-color
haciendo lo siguiente:
var bodyStyles = document.body.style; bodyStyles.setProperty('--text-color', 'white'); bodyStyles.setProperty('--background-color', 'black');
En los años de desarrollo y charlas sobre las especificaciones de las propiedades personalizadas de CSS, han surgido algunos casos de uso interesantes. Estos son algunos ejemplos:
Cambio de tema: usar un conjunto de temas para un sitio es bastante fácil si se implementan las variables CSS. ¿Querés cambiar el estilo actual por un tema claro o uno oscuro? Simplemente cambiá el valor de algunas propiedades personalizadas usando JavaScript, y listo.
Ajuste de espacios: ¿Necesitás configurar el espaciado de un sitio, por ejemplo, los espacios entre columnas? Cambiá el valor de una sola variable CSS y podrás ver este cambio reflejado en todo el sitio.
Funciones calc() totalmente dinámicas: ahora podés tener funciones calc()
totalmente dinámicas usando las propiedades personalizadas dentro de estas funciones. Con esto, ya no tendrás que hacer cálculos efímeros o complicados en JavaScript y luego actualizar los valores manualmente en cada caso.
Las propiedades personalizadas de CSS son una forma potente e innovadora de darles más vida a tus hojas de estilo e insertan valores totalmente dinámicos en CSS por primera vez.
La especificación se encuentra en estado de “recomendación de candidato”, lo que significa que la estandarización está por llegar. Esta es una buena razón para ahondar en la herramienta y aprovecharla al máximo.
Nota: tal como señaló Lea Verou el 22 de abril, ahora la mayoría de los navegadores principales soportan las propiedades personalizadas por defecto sin la necesidad de cambiar un indicador. Su uso para la producción es seguro, a menos que se necesite un soporte para versiones de navegadores más antiguas.