Curso de CSS / variables: var(), alcance, herencia y valores de respaldo

Las propiedades personalizadas de CSS almacenan valores reutilizables y se referencian con var() en valores de propiedades. Su alcance sigue la cascada y la herencia, y un valor de respaldo de var() no rescata automáticamente un valor definido que sea inválido para la propiedad receptora.

Elige variables compartidas significativas

Si usas el mismo color de acento para múltiples botones y tarjetas, puedes agruparlo en una variable significativa en lugar de copiar el código de color en cada selector. Al cambiar el color de acento, si modificas una declaración, el lugar que referencia ese valor también cambia. Si creas variables, incluso valores que solo se usan en un lugar y no tienen un rol separado, la carga de mantener un seguimiento de los nombres puede en realidad aumentar.

:root {
  --accent: #1d5f91;
  --space-unit: .5rem;
}
.button { color: white; background: var(--accent); }
.card { border: 2px solid var(--accent); padding: calc(var(--space-unit) * 3); }

Simplemente declarar un color en el código anterior no cambia la pantalla. Usa var() en una propiedad real, como background o border, para aplicar el valor almacenado. Si el nombre indica el rol, como --accent, en lugar de fijar el color actual, como --blue, será menos confuso al cambiar a un color diferente más adelante. --accent y --Accent son nombres diferentes, así que respeta las mayúsculas y la ortografía.

var() se utiliza para el valor de propiedades como color o padding. No se pueden reemplazar selectores o nombres de propiedades con variables, y no se puede usar una variable para definir el umbral de @media (min-width: ...) ni usar var() en el valor de condición de una consulta de tamaño de contenedor. Escribe los puntos de cambio directamente en la declaración condicional correspondiente y distínguelos de los valores a los que se pueden aplicar variables, como el color o el espaciado de los elementos.

Comprende el alcance de raíz, herencia y componentes

En un documento HTML, :root coincide con el elemento HTML de nivel superior, por lo que es conveniente tener un valor predeterminado común en el documento. Las propiedades personalizadas no registradas del ejemplo, con nombres que empiezan por --, se heredan a los descendientes. Los valores declarados dentro de una tarjeta pueden ser utilizados por los descendientes, como el título, pero no se transmiten a tarjetas hermanas no relacionadas.

.card { --card-accent: var(--accent); }
.card.warning { --card-accent: #a63e32; }
.card { border-color: var(--card-accent); }
.card h2 { color: var(--card-accent); }

Esta regla es una parte componente del ejemplo completo a continuación. .card.warning coincide con tarjetas que tienen ambas clases. Ganar o perder no se determina por el orden de listado de las clases HTML, sino por aplicar las reglas de herencia, especificidad y cascada de CSS. Cambiar el acento global cambiará la tarjeta predeterminada, y las tarjetas de advertencia con su propio card-accent retendrán sus colores de advertencia originales.

Al combinar variables con otras variables, también es importante de qué elemento se calcula el valor. Si --line-color: var(--accent) se calcula en el elemento padre y luego se pasa al hijo, el color de línea ya heredado no siempre se recalculará solo porque el acento se sobrescriba en el hijo. Los valores derivados que deberían seguir el acento de sus descendientes, obviamente, es mejor declararlos en el elemento o haciendo referencia directamente al acento en la propiedad CSS que lo usa. Para definiciones de alcance y herencia, consulta Especificación de propiedad personalizada de CSS.

Distingue entre valores de respaldo y valores computados no válidos

var(--notice-color, #6a3989) proporciona un valor de respaldo púrpura cuando falta un valor de variable y no se puede usar. Incluso si una variable está definida y tiene un valor significativo en otras propiedades, como 20px, si el valor no coincide con el color, la declaración de color se vuelve inválida en el momento del cálculo. En este caso, no deberías esperar ser "reemplazado por púrpura".

estado de la variable Resultado de la declaración de color Colores para todo el ejemplo
--notice-color sin definir Usando valores de respaldo para var púrpura
--notice-color contiene un color válido Usar valores definidos rojo
--notice-color: 20px Se aplican reglas de herencia/valor inicial porque no coincide con el color Como color se hereda, se usa el verde del padre.

Como se muestra a continuación, incluso si hay una declaración azul primero en la misma regla, si el valor después de la sustitución de la variable en la segunda declaración no coincide, no volverá al primer azul. Después de que la declaración seleccionada en la cascada sea inválida en el momento de la evaluación, se aplican las reglas de herencia del color. En la misma situación, una propiedad que no se hereda puede ser tratada como el valor inicial de esa propiedad. MDN Guía de Propiedades Personalizadas explica la diferencia entre valores de reemplazo y valores inválidos.

.sample {
  color: #1d5f91;
  color: var(--notice-color, #6a3989);
}
.sample.bad { --notice-color: 20px; }

También puedes poner otras variables en el valor de respaldo. Por ejemplo, var(--button-accent, var(--accent, #1d5f91)) busca el valor a usar, comenzando con el valor específico del botón, luego el valor común y finalmente el color primario. Sin embargo, si se mezclan los usos de números, longitudes y colores, ocurre el mismo problema, por lo que los nombres de las variables y su uso deben gestionarse juntos.

Combina valores y unidades con calc()

El ejemplo multiplica --space-unit: .5rem por 3 para establecer el padding de la tarjeta. rem usa el tamaño de fuente raíz, por lo que cambiar ese tamaño cambia el espaciado. Usa calc() para el cálculo en lugar de concatenar cadenas, y deja espacios alrededor de los operadores de suma y resta. Para más detalles, consulta colores y unidades CSS: px, em, rem y porcentajes.

:root {
  --space-unit: .5rem;
  --space-card: calc(var(--space-unit) * 3);
}
.card { padding: var(--space-card); }

Elige de forma coherente si las variables incluyen unidades o solo números. Si introduces un valor sin unidad como 2 en la variable de longitud, puede que no sea adecuado para aplicaciones que requieran unidades. Evita combinaciones de diferentes usos, como aplicar calc a una variable que contenga un color. Para la sintaxis básica de la fórmula, consulta el documento MDN calc.

Ejecuta la comparación de alcance y valores de respaldo

Guarda el siguiente código como custom-properties.html en UTF-8 y ábrelo en el navegador. Compara los colores de acento de las dos tarjetas y los colores de texto de las tres oraciones. El texto de cada caso describe su resultado, para no depender solo del color.

<!doctype html>
<html lang="en">
<head>
  <meta charset="utf-8">
  <meta name="viewport" content="width=device-width, initial-scale=1">
  <title>CSS variable scope and substitution values</title>
  <style>
*, *::before, *::after { box-sizing: border-box; }
body { margin: 0; padding: 1rem; color: #183044; font-family: sans-serif; line-height: 1.6; }
main { max-width: 46rem; margin-inline: auto; }
h1 { font-size: 1.5rem; } h2 { font-size: 1.2rem; }
button, input { font: inherit; }
button { cursor: pointer; }
:focus-visible { outline: 3px solid #164f73; outline-offset: 3px; }
:root { --space-unit: .5rem; --space-card: calc(var(--space-unit) * 3); --accent: #1d5f91; }
.cards { display: grid; gap: 1rem; }
.card { --card-accent: var(--accent); padding: var(--space-card); border: 2px solid var(--card-accent);
  border-radius: .5rem; background: #f6f9fb; }
.card h2 { color: var(--card-accent); margin-block: 0 .5rem; }
.card p { margin: 0; }
.card.warning { --card-accent: #a63e32; }
.fallback-area { margin-block: 2rem; padding: 1rem; border: 1px solid #8a9ba7; color: #28633b; }
.sample { color: #1d5f91; color: var(--notice-color, #6a3989); }
.sample.bad { --notice-color: 20px; }
.sample.good { --notice-color: #a63e32; }
  </style>
</head>
<body>
<main>
<h1>Variable scope and fallbacks</h1>
<div class="cards">
  <article class="card"><h2>Basic card</h2><p>The heading and border share the same accent color.</p></article>
  <article class="card warning"><h2>warning card</h2><p>The accent color changes only inside this card.</p></article>
</div>
<section class="fallback-area">
  <h2>The parent's text color is green</h2>
  <p class="sample missing">Undefined: purple fallback</p>
  <p class="sample bad">20px: Doesn't match the color, so it inherits the green color from the parent.</p>
  <p class="sample good">Defined as red: use that color</p>
</section>
</main>
</body>
</html>
  1. Asegúrate de que el título y el borde de las tarjetas básicas sean azules y que las tarjetas de advertencia sean rojas. Las tres oraciones a continuación son de color púrpura, verde y rojo, respectivamente.
  2. Cambia solo el acento raíz a #28633b. El encabezado y el borde de la tarjeta predeterminada deberían cambiar, mientras que la tarjeta de advertencia mantiene su propio color de advertencia. Restaura el acento raíz a #1d5f91 después de verificar.
  3. Cambia solo --space-unit a 1rem. Los rellenos de ambas tarjetas se estiran juntos. Después de la confirmación, restaura a .5rem.
  4. Cambia solo --notice-color de .sample.bad de 20px a #1d5f91. La oración cambiará de verde a azul. Después de la confirmación, restáurala a 20px.
  5. Elimina únicamente la declaración --notice-color de .sample.bad. Esta vez se usa un valor de reserva púrpura. Compara con el resultado azul del paso anterior y restaura la declaración original.

Diagnostica variables faltantes o incorrectas

  • En las herramientas de desarrollo, verifica si el nombre de la variable y su valor existen realmente en ese elemento. Revisa primero la ortografía, la capitalización y el alcance de la declaración.
  • Verifica si los descendientes u otras reglas sobrescriben la misma variable. Puede que no sea un error que un componente mantenga sus valores únicos aunque su valor común cambie.
  • Comprueba si la variable se referencia en la propiedad actual y si las unidades y el tipo del valor sustituido son correctos.
  • Si se crea un valor a través de múltiples variables, verifica el elemento calculado y el valor heredado. También evita declaraciones que se refieran a la misma variable que ellas mismas o que se refieran de manera circular.

Puedes aprovechar las variables distinguiendo entre colores comunes y espaciado del diseño y excepciones para cada componente, y verificando los resultados antes y después del cambio. En lugar de aumentar el número de nombres de variables, es más útil para el mantenimiento dejar claro qué valores se comparten en qué ámbito.