Sobrescribir una variable CSS en un elemento hijo no reconstruye una propiedad personalizada compuesta heredada de su elemento padre. El padre ya ha resuelto la referencia anidada. Para usar el valor del hijo, declara la propiedad compuesta en ese hijo o construye allí la propiedad final.
Esta guía explica ese comportamiento y ofrece un ejercicio de escritorio reproducible en Chrome para Mac. La tarea consiste en hacer que el borde de un componente siga su anulación local del color y, a la vez, conserve los valores predeterminados compartidos.
¿Por qué la propiedad compuesta heredada conserva el color del padre?
Considera este fragmento de CSS. Se presupone que hay un elemento .sample-tile dentro de un elemento .sample-board:
.sample-board {
--sample-color: teal;
--sample-border: 6px solid var(--sample-color);
}
.sample-tile {
--sample-color: darkorange;
border: var(--sample-border);
}
El borde del hijo sigue siendo verde azulado. La especificación de Variables CSS establece que las propiedades personalizadas resuelven sus funciones anidadas var() en el momento del valor calculado, antes de la herencia. Por consiguiente, el hijo hereda una propiedad compuesta equivalente a 6px solid teal; no hereda una expresión que sustituya --sample-color por el valor del hijo. Propiedades personalizadas CSS para variables en cascada, nivel 1.
Aquí hay dos propiedades distintas. Establecer --sample-color en el hijo cambia el valor local de esa propiedad. No declara también un valor nuevo para --sample-border. La referencia de MDN sobre propiedades personalizadas describe las propiedades personalizadas ordinarias no registradas como heredadas, con valores calculados en los que se sustituyen las variables. Propiedades personalizadas: variables CSS.
La secuencia de este ejemplo es:
- El padre calcula
--sample-colorcomoteal. - Su
--sample-bordersustituye ese color y produce6px solid teal. - El hijo hereda esa propiedad compuesta y establece por separado su propio token de color en
darkorange. - La declaración
borderdel hijo utiliza la propiedad compuesta verde azulada heredada.
Esto no es una instantánea permanente del padre. Si cambia el color del padre, su propiedad compuesta puede actualizarse y volver a heredarse. El límite es el elemento donde se resuelve la referencia anidada: una anulación en un descendiente no modifica ese cálculo desde arriba. Variables CSS: resolución de dependencias.
Reproduce el comportamiento en Chrome para Mac
Usa una página en blanco para que los estilos existentes no interfieran. Abre una nueva pestaña de Chrome, escribe about:blank en la barra de direcciones y luego pulsa Command + Option + J para abrir la Consola. Google documenta este atajo para Mac en su guía de DevTools. Abrir Chrome DevTools.
El siguiente programa completo para la consola del navegador crea tres formas abstractas con etiquetas y su hoja de estilos. No necesita bibliotecas, imágenes, solicitudes de red ni elementos existentes en la página. Ejecuta el bloque completo una vez en la página en blanco. Los resultados esperados que se indican a continuación se deducen de las reglas CSS documentadas; no se presentan como mediciones realizadas en un navegador.
(() => {
const board = document.createElement("section");
board.className = "sample-board";
const style = document.createElement("style");
style.textContent = `
.sample-board {
--sample-color: teal;
--sample-border: 6px solid var(--sample-color);
display: flex;
flex-wrap: wrap;
gap: 24px;
padding: 32px;
font: 16px system-ui;
}
.sample-board .sample-tile {
--sample-color: darkorange;
display: grid;
place-items: center;
width: 120px;
height: 80px;
border: var(--sample-border);
border-radius: 24px;
background: white;
color: black;
}
.sample-board .sample-local {
--sample-border: 6px solid var(--sample-color);
}
.sample-board .sample-direct {
border: 6px solid var(--sample-color);
}
`;
const samples = [
["Inherited", "sample-inherited"],
["Local", "sample-local"],
["Direct", "sample-direct"]
];
const tiles = samples.map(([label, className]) => {
const tile = document.createElement("div");
tile.className = `sample-tile ${className}`;
tile.textContent = label;
board.append(tile);
return tile;
});
document.head.append(style);
document.body.append(board);
function report(stage) {
console.log(stage);
console.table(tiles.map((tile) => {
const computed = getComputedStyle(tile);
return {
sample: tile.textContent,
localColor: computed
.getPropertyValue("--sample-color").trim(),
composite: computed
.getPropertyValue("--sample-border").trim(),
paintedBorder: computed.borderTopColor
};
}));
}
report("Initial values");
board.style.setProperty("--sample-color", "rebeccapurple");
report("After changing the parent color");
})();
El programa imprime dos tablas. Los colores de borde esperados son:
| Muestra | Al inicio | Tras cambiar el padre | Motivo |
|---|---|---|---|
Inherited |
Verde azulado | Morado | Usa la propiedad compuesta calculada del padre |
Local |
Naranja | Naranja | Declara la propiedad compuesta en el hijo |
Direct |
Naranja | Naranja | Sustituye el color local directamente en border |
Los tres hijos conservan darkorange como token de color local. La muestra Direct es el diagnóstico útil: su propiedad compuesta heredada sigue conteniendo el color del padre, pero el borde renderizado usa el token local porque la declaración del borde no utiliza la propiedad compuesta.
getComputedStyle() lee los valores de propiedades resueltos después de aplicar las hojas de estilo activas. Por eso puede mostrar lo que un elemento recibe realmente, en vez de limitarse a mostrar la expresión escrita en el código. El color serializado puede aparecer como un valor rgb() en lugar del nombre original del color. Window: método getComputedStyle().
Vuelve a cargar la pestaña en blanco para borrar el ejercicio. En una página propia, coloca la solución CSS elegida en su hoja de estilos; los cambios en la consola sirven para diagnosticar, pero no editan los archivos de origen.
¿Qué solución deberías elegir?
Declara la propiedad compuesta en el límite del componente
La muestra Local conserva el token de borde reutilizable y declara su composición en el mismo elemento que proporciona la anulación. Este es el fragmento CSS pertinente del programa:
.sample-board .sample-local {
--sample-color: darkorange;
--sample-border: 6px solid var(--sample-color);
border: var(--sample-border);
}
Elige este patrón cuando varias declaraciones necesiten el mismo valor compuesto. Coloca los valores predeterminados primitivos en un ancestro y declara la propiedad compuesta en el componente que controla la personalización. Las propiedades personalizadas se pueden declarar en elementos concretos y heredarse por sus descendientes; no tienen que estar en :root. Uso de propiedades personalizadas CSS.
La ubicación sigue siendo importante más abajo en el árbol. Si un nieto vuelve a anular el valor primitivo, una propiedad compuesta heredada de este componente seguirá reflejando el cálculo de este componente. Vuelve a declarar la composición en cualquier límite descendiente que deba generar un resultado distinto.
Construye la propiedad final donde se usa
La muestra Direct elimina el token intermedio de la declaración del borde. Este fragmento CSS contiene su regla esencial:
.sample-board .sample-direct {
--sample-color: darkorange;
border: 6px solid var(--sample-color);
}
Elige esta opción cuando solo una declaración necesite la combinación. Puedes seguir compartiendo tokens separados para el ancho, el estilo y el color, y luego combinarlos en la declaración border del componente. MDN documenta que var() puede sustituir todo o parte del valor de otra propiedad. Uso de propiedades personalizadas CSS.
Anula la propiedad compuesta completa si es el control público
A veces, la personalización prevista para el componente es el borde completo. En ese caso, proporciona un reemplazo local para --sample-border, como 6px solid darkorange, en lugar de cambiar solo el valor que antes lo alimentaba.
Usa esta guía de decisión para elegir el contrato del componente:
| Personalización prevista | Patrón adecuado |
|---|---|
| Un color local controla un borde | Componer directamente en border |
| Varias declaraciones comparten un valor compuesto | Declarar la propiedad compuesta en el componente |
| Quien usa el componente proporciona el borde completo | Anular la propiedad compuesta directamente |
| Los descendientes deben usar exactamente el valor compuesto del padre | Conservar la propiedad compuesta heredada |
¿Por qué la especificidad, los valores alternativos o las palabras clave de herencia no la reconstruyen?
Primero, confirma que la anulación del valor primitivo haya prevalecido. Si el valor resuelto de --sample-color en el hijo ya es darkorange, aumentar la especificidad de esa misma declaración no cambiará la propiedad --sample-border heredada por separado. Ambas propiedades ya tienen valores; el problema es dónde se compuso el borde.
Del mismo modo, --sample-border: inherit toma el valor calculado del padre. La herencia ordinaria transfiere valores calculados, en lugar de volver a ejecutar la declaración escrita del padre en el contexto del hijo. Herencia.
Un valor alternativo como var(--sample-border, 6px solid darkorange) tampoco reemplaza un borde verde azulado heredado válido. Un valor alternativo var() se aplica cuando una propiedad personalizada no tiene un valor utilizable; no compara ese valor con los valores de entrada preferidos de un descendiente. Función CSS var().
Mantén los valores no válidos separados de este problema de herencia. Por ejemplo, un token no registrado que contiene 12px puede existir como valor de una propiedad personalizada y, aun así, producir un resultado no válido al sustituirse en border-color. El valor alternativo dentro de esa llamada a var() no es una alternativa general para validar tipos. MDN explica por qué la sustitución de propiedades personalizadas puede crear declaraciones que se vuelven no válidas en el momento del valor calculado. Uso de propiedades personalizadas CSS.
¿Registrar la variable con @property resuelve esto?
@property permite especificar la sintaxis, el valor inicial y el comportamiento de herencia de una propiedad personalizada. No hace que una propiedad compuesta heredada del padre se vuelva a evaluar con los valores de entrada anulados por el hijo. Registrar la propiedad primitiva con inherits: false cambiaría cómo se obtiene ese valor primitivo, mientras que registrar así la propiedad compuesta detendría su herencia normal. Ninguna de las dos opciones proporciona la composición local que falta. Regla at CSS @property.
El registro también tiene un límite de compatibilidad distinto. MDN indica que las propiedades personalizadas ordinarias están ampliamente disponibles en los navegadores desde abril de 2017, mientras que @property alcanzó la disponibilidad Baseline en julio de 2024 y puede no estar disponible en navegadores más antiguos. Las dos soluciones mostradas no requieren registro. Propiedades personalizadas: variables CSS, Regla at CSS @property.
Cómo diagnosticar el mismo problema en tu hoja de estilos
Usa la comparación de tres columnas del ejercicio en el elemento cuya apariencia es incorrecta:
- Lee el token primitivo, como
--sample-color. - Lee el token compuesto, como
--sample-border. - Lee la propiedad renderizada, como
border-top-color. - Busca el elemento al que se aplica la declaración compuesta.
- Mueve o repite esa declaración en el límite de personalización previsto, o compón directamente la propiedad final.
Para localizar las reglas pertinentes en Chrome, haz clic derecho en la forma y selecciona Inspeccionar. DevTools selecciona el elemento en Elements y la pestaña Styles muestra las reglas CSS que se le aplican. Abrir Chrome DevTools.
Cuando el valor primitivo muestra el valor local deseado, pero la propiedad compuesta sigue conteniendo el valor de un ancestro, inspecciona primero dónde se declara la propiedad compuesta. Define la composición donde deban leerse sus valores de entrada y luego comprueba tanto el token resuelto como el resultado renderizado. Así, el componente tiene un límite de personalización explícito y predecible.
Fuentes
- Propiedades personalizadas CSS para variables en cascada, nivel 1 — W3C.
- Propiedades personalizadas (--*): variables CSS — MDN Web Docs.
- Uso de propiedades personalizadas (variables) CSS — MDN Web Docs.
- Herencia — MDN Web Docs.
- Función CSS var() — MDN Web Docs.
- Regla at CSS @property — MDN Web Docs.
- Window: método getComputedStyle() — MDN Web Docs.
- Abrir Chrome DevTools — Chrome for Developers.