Cómo usar las nuevas variables CSS

Las variables CSS, técnicamente llamadas "propiedades CSS no estándar", simplifican tus archivos CSS y permiten crear efectos tan interesantes como cambiar dinámicamente los estilos aplicados en una página y mejorar las características de las propiedades CSS estándar.

Google Chrome era el único navegador importante que todavía no soportaba estas variables CSS. Sin embargo, a partir de su versión 49 ya están disponibles, por lo que ya es seguro usar variables CSS si tus usuarios usan navegadores modernos (Firefox 43+, Safari 9.1+, iOS Safari 9.3+, Chrome 49+).

Por qué son necesarias estas variables

Cuando se diseña un sitio o aplicación web es habitual reutilizar una serie de colores para dar consistencia al diseño. El problema es que repetir los mismos colores una y otra vez no solo es muy aburrido sino que es muy propenso a cometer errores. Cuando quieras cambiar un color, aunque hagas un "Buscar y reemplazar" en tu editor de código, seguro que te dejarás sin cambiar algún color en algún archivo.

Por supuesto desde hace tiempo muchos diseñadores usan preprocesadores como Sass o LESS y definen variables para guardar estos valores. Sin embargo, estas variables tienen una limitación muy importante: no se pueden modificar en tiempo real mientras la página se muestra en el navegador.

Las variables CSS sí que permiten estos cambios en tiempo real, por lo que es posible por ejemplo diseñar varios temas para el sitio de manera que el usuario pueda elegir el estilo que más le guste.

Las variables CSS en la práctica

Las variables CSS añaden dos nuevas funcionalidades a los archivos CSS tradicionales:

  • Permiten asignar cualquier valor a una propiedad cuyo nombre podemos elegir libremente.
  • Permiten reutilizar esos valores en cualquier otra propiedad gracias a la función var()

Este ejemplo sencillo muestra cómo definir y usar una variable CSS:

:root {
  --color-principal: #06c;
}
 
#foo h1 {
  color: var(--color-principal);
}

--color-principal es una propiedad CSS definida arbitrariamente por el creador de esta hoja de estilos y cuyo valor es #06c. Aunque puedes elegir cualquier nombre para las variables, estos siempre tienen que empezar con dos guiones medios (--).

La función var() obtiene el valor de la propiedad cuyo nombre se indica y lo inserta en el lugar donde se llama a la función. De esta manera, el ejemplo anterior es equivalente a:

#foo h1 {
  color: #06c;
}

La sintaxis de las variables CSS resulta un poco extraña al principio. La pregunta más habitual suele ser: ¿y por qué no se puede declarar la variable simplemente como $foo en vez de --foo? La respuesta es que la sintaxis $foo está reservada para en el futuro poder definir "macros", tal y como se explica en este artículo.

Sintaxis de las variables CSS

La sintaxis que definen las variables CSS o "propiedades CSS no estándar" es muy simple:

--color-cabecera: #06c;

El nombre de las propiedades distingue mayúsculas de minúsculas, por lo que --color-cabecera y --color-Cabecera se consideran diferentes propiedades. No pienses que estas variables solo sirven para guardar valores simples. Por ejemplo, la siguiente sintaxis también es válida:

--foo: if(x > 5) this.width = 10;

Aunque esta propiedad no sería útil como variable CSS, y aunque no se puede usar como valor de ninguna otra propiedad CSS, este valor podría procesarse en el navegador mediante JavaScript para ejecutar alguna tarea compleja. Esta funcionalidad abre la puerta a muchos trucos y técnicas avanzadas que son imposibles con los preprocesadores CSS actuales (Sass y LESS).

Herencia

Las propiedades CSS no estándar también siguen las mismas reglas de "herencia en cascada" de las propiedades CSS estándar, por lo que puedes definir la misma variable con diferentes niveles de especificidad:

:root { --color: blue; }
div { --color: green; }
#alert { --color: red; }
* { color: var(--color); }
<p>Este contenido se ve azul (definido por ":root")</p>
<div>Este contenido se ve verde (definido por "div")</div>
<div id="alert">
  Este contenido se ve rojo (definido por "#alert")
  <p>este contenido también se ve rojo
     (heredado de su elemento padre)</p>
</div>

De esta manera, puedes combinar las variables CSS con las media queries en tus diseños "responsive". El siguiente ejemplo muestra cómo incrementar el margen de un elemento a medida que el tamaño de la pantalla aumenta:

:root {
  --separacion: 4px;
}
 
section {
  margin: var(--separacion);
}
 
@media (min-width: 600px) {
  :root {
    --separacion: 16px;
  }
}

Este ejemplo de nuevo es imposible de hacer con los preprocesadores, ya que no se pueden definir variables dentro de los media queries.

Por otra parte, el valor de una variable se puede definir a partir de otras variables, lo que es muy útil para definir el tema de un sitio:

:root {
  --color-principal: red;
  --texto-logotipo: var(--color-principal);
}

La función var()

La función var() obtiene el valor de la propiedad indicada. Su sintaxis completa es la siguiente:

var(<nombre-propiedad> [, <valor-por-defecto> ]? )

El primer argumento (<nombre-propiedad>) es el nombre completo de la propiedad cuyo valor se quiere obtener. El segundo argumento (<valor-por-defecto>) es opcional y es el valor utilizado cuando la propiedad no existe.

El valor por defecto puede ser en realidad una lista de varios valores separados por comas. Por ejemplo, si utilizas var(--font-stack, "Roboto", "Helvetica"); y la propiedad --font-stack no existe, el valor devuelto será "Roboto", "Helvetica" todo junto.

Cuidado con los atajos en las propiedades CSS como margin y padding. En este caso, como sus valores no están separados por comas, el valor por defecto tampoco debe contener comas. Ejemplo:

p {
  padding: var(--separacion, 10px 15px 20px);
}

Los valores por defecto son muy útiles al diseñar componentes, ya que permiten realizar un "diseño defensivo" que está preparado frente a los errores ajenos. Ejemplo:

/* Estilos definidos por el componente: */
.component .header {
  color: var(--color-cabecera, blue);
}
.component .text {
  color: var(--color-texto, black);
}
 
/* estilos de la aplicación: */
.component {
  --color-texto: #080;
  /* la variable --color-cabecera no está definida en la aplicación,
     así que se usará el valor por defecto definido en el componente */
}

Esta técnica también es útil para aplicar temas a los componentes que usan "Shadow DOM". El diseñador del componente crea un estilo inicial con los valores por defecto y después permite su personalización mediante algunas variables CSS:

<!-- definición del componente web: -->
<x-foo>
  #shadow
    <style>
      p {
        background-color: var(--color-fondo-texto, blue);
      }
    </style>
 
    <p>
      Este texto tiene un color de fondo amarillo porque la aplicación
      así lo ha definido. Si no, el fondo sería de color azul.
    </p>
</x-foo>
/* en los estilos de la aplicación: */
x-foo {
  --color-fondo-texto: yellow;
}

La función var() también tiene algunas limitaciones. En primer lugar, las variables no se pueden usar como nombre de la propiedad CSS. Por eso el siguiente ejemplo no es equivalente al estilo margin-top: 20px; y el navegador mostraría un mensaje de error:

.foo {
  --lado: margin-top;
  var(--lado): 20px;
}

Igualmente, no puedes usar el valor de una variable como parte del valor de una propiedad. Por eso el siguiente ejemplo tampoco es equivalente a margin-top: 20px y el navegador mostraría un mensaje de error:

.foo {
  --separacion: 20;
  margin-top: var(--separacion)px;
}

En este último caso, la solución sería utilizar otra función llamada calc(), tal y como se explica en la siguiente sección.

Generando valores con la función calc()

La función calc() es muy útil para realizar cálculos al definir los valores de las propiedades CSS. Todos los navegadores modernos la soportan sin problemas y se puede combinar con las variables CSS. Ejemplo:

.foo {
  --separacion: 20;
  margin-top: calc(var(--separacion) * 1px);
}

Usando variables CSS con JavaScript

El valor de las variables CSS se puede obtener en JavaScript mediante el método getPropertyValue() del objeto CSSStyleDeclaration. Ejemplo:

:root {
  --color-principal: red;
}
 
p {
  color: var(--color-principal);
}
<p>Este párrafo es de color rojo.</p>
var estilosCss = getComputedStyle(document.documentElement);
var valor = String(estilosCss.getPropertyValue('--color-principal')).trim();
// valor = 'red'

Igualmente, para cambiar el valor de una variable CSS en el propio navegador, utiliza el método setProperty() del objeto CSSStyleDeclaration.

:root {
  --color-principal: red;
}
 
p {
  color: var(--color-principal);
}
<p>Este párrafo ahora es de color verde.</p>
document.documentElement.style.setProperty('--color-principal', 'green');

Añade la función var() en la llamada al método setProperty() para usar el valor de una variable CSS como valor de otra variable CSS:

:root {
  --color-principal: red;
  --color-secundario: blue;
}
<p>Y ahora este párrafo es de color azul.</p>
document.documentElement.style.setProperty(
  '--color-principal', 'var(--color-secundario)'
);

Como además las variables CSS pueden hacer referencia a otras variables CSS de otras hojas de estilos, esta manipulación en tiempo real mediante JavaScript permite realizar comportamientos dinámicos muy avanzados.

Sobre el autor

Este artículo fue publicado originalmente por Rob Dodson y ha sido traducido con permiso por Javier Eguiluz.

Comentarios