De dónde provienen los valores CSS cuando se establece “None”: cómo funciona la herencia
Aprenda cómo deciden los navegadores si una propiedad hereda, por qué los hijos reciben el valor calculado del padre, y cómo inherit e initial le brindan un control explícito.
Fuentes: How Inheritance Works in CSS Internally at Algorithmic Level.
Estableces el color en un contenedor, y el párrafo dentro se vuelve rojo aunque ninguna regla lo mencione. Mientras tanto, el relleno que le asignas a ese mismo contenedor permanece exactamente donde está. Ambos comportamientos provienen de la herencia en CSS, el mecanismo que asigna un valor cuando un elemento no tiene ninguno propio. Esta guía explica qué propiedades se heredan, qué es exactamente lo que se transmite (la respuesta sorprende a muchas personas cuando están involucradas las porcentajes), cómo las palabras clave inherit y initial modifican el valor por defecto, y dónde encaja la herencia entre las demás etapas que convierten una hoja de estilo en valores finales.
Un valor que nadie declaró
Comienza con una regla en un elemento padre:
.parent {
color: red;
}
y el marcado donde se encuentra el párrafo dentro de ese padre:
<div class="parent">
<p>Hello World</p>
</div>
No hay conjuntos de reglas que establezcan el color en el <p>, sin embargo su texto se muestra en rojo. Para cuando el navegador llega a este punto, ya ha resuelto las declaraciones conflictivas mediante la cascada y procesado sus valores. Lo que queda es decidir, para cada propiedad de cada elemento, si el valor debe provenir de las declaraciones propias del elemento o de algún nivel superior en la estructura. La herencia es el mecanismo que permite tomar esa decisión.
¿Qué valores se transmiten por la estructura?
La herencia permite que ciertos valores de propiedad pasen de un elemento padre a sus hijos, y de allí a los hijos de estos a su vez:
Parent
↓
Child
↓
Grandchild
No todas las propiedades participan en este proceso. Las propiedades que describen el texto son las clásicas que se heredan, como por ejemplo:
font-family
font-size
color
Por esta razón rara vez es necesario repetir la tipografía en cada elemento. En lugar de establecer el mismo color en el body y luego nuevamente en cada tipo de elemento hijo:
body {
color: #333;
}
h1 {
color: #333;
}
p {
color: #333;
}
li {
color: #333;
}
puedes declararlo una sola vez, en la parte superior del árbol del documento, y dejar que la herencia lo transmita hacia abajo. El resultado es menos CSS y un único lugar donde realizar cambios cuando se modifica el diseño. Establecer la fuente y el color base en body o :root es la aplicación cotidiana de esta idea.
La decisión que toma el navegador para cada propiedad
La lógica se vuelve más clara al analizar el caso en el que no hay declaración aplicable a un elemento. Para cada propiedad, el navegador efectivamente hace dos preguntas en orden.
Primero: ¿existe un valor en cascada? Si alguna declaración para esta propiedad ganó la cascada en este elemento, se utiliza ese valor y la herencia nunca entra en juego.
Segundo, solo si la respuesta fue no: ¿se hereda esta propiedad? Eso depende completamente de la propiedad, ya que cada una está definida como heredada o no heredada por la especificación. Algunos ejemplos de propiedades heredadas:
color → inherited
font-family → inherited
font-size → inherited
y algunas que no se heredan:
margin → not inherited
padding → not inherited
La separación es intencionada. Imagina un mundo en el que margin se heredara: un único margen en una sección se copiaría a cada párrafo, lista y enlace anidado dentro de ella, y el espaciado se acumularía en cada nivel. Las propiedades relacionadas con los contenedores, como margin, padding, border y width, son casi siempre cosas que deseas establecer por elemento, mientras que las propiedades relacionadas con el texto suelen aplicarse a toda una región. Si una propiedad no se hereda y no tiene un valor en cascada, adopta su valor inicial, el predeterminado definido para esa propiedad.
Si no estás seguro acerca de una propiedad específica, la entrada “Heredado” en su documentación de referencia responde directamente a la pregunta.
Los hijos heredan el valor calculado, no el texto que escribiste
Este es el detalle más importante de todo el proceso, y el responsable de una sorpresa bien conocida. Supongamos que un padre establece un tamaño de fuente y una altura de línea en porcentaje:
.parent {
font-size: 20px;
line-height: 150%;
}
y un hijo sobrescribe solo el tamaño de fuente:
.child {
font-size: 25px;
}
¿Qué altura de línea tendrá el hijo al final? Una suposición intuitiva es que el hijo recibe el porcentaje en sí:
150%
y luego lo ajusta según su propio tamaño de fuente, que es mayor:
150% of 25px
Así no funciona. Lo que hereda un elemento es el valor calculado de su padre, no el valor tal como fue declarado. Para line-height, un porcentaje se convierte en una longitud en el momento del cálculo del valor calculado. En el padre, el cálculo es:
150% of 20px = 30px
por lo que la altura de línea calculada del padre es:
30px
Esa longitud absoluta es la que se transmite. El elemento hijo, a pesar de su fuente más grande, hereda una altura de línea de:
30px
y no:
150% of 25px
La consecuencia práctica es que las líneas se ven estrechas cada vez que un elemento descendiente utiliza una fuente más grande que el elemento donde se declaró el porcentaje. Lo mismo ocurre con los valores em para line-height, ya que también se convierten en longitudes antes de la herencia. Por esta razón exacta, las alturas de línea sin unidades como line-height: 1.5 son la recomendación habitual: un número simple es en sí mismo el valor calculado, de modo que cada elemento descendiente lo multiplica por su propio tamaño de fuente en lugar de heredar una longitud fija.
Las propiedades que no se heredan vuelven a su valor inicial
Ahora tomemos una propiedad del otro grupo:
padding
El relleno no se hereda. Por lo tanto, cuando un padre declara:
.parent {
padding: 20px;
}
el hijo no recibe automáticamente ese valor:
padding: 20px;
En su lugar, al no haber valor en cascada ni herencia, el relleno del hijo utiliza el valor inicial de la propiedad, que para el relleno es:
0px
Esto se mantiene a menos que alguna otra regla le proporcione explícitamente al hijo un relleno diferente. Saber en qué categoría cae una propiedad ahorra tiempo al depurar: si un valor parece “filtrarse” a los hijos, se trata de una propiedad heredada; si parece “desaparecer” en los hijos, es una no heredada. Las herramientas de desarrollo del navegador ayudan aquí, ya que el panel Computed puede mostrar los valores heredados junto con su ancestro.
Forzando la herencia con inherit
Puede sobrescribir el comportamiento predeterminado de cualquier propiedad. La palabra clave inherit indica al navegador que utilice el valor del padre, incluso para una propiedad que normalmente no heredaría ese valor:
.child {
padding: inherit;
}
Con esta regla, el relleno del elemento hijo coincide con el relleno calculado del padre. Es útil cuando se desea que la relación entre el padre y el hijo sea explícita, por ejemplo para hacer que un elemento anidado reutilice el color del borde o el espaciado de su contenedor, o para forzar a los controles de formulario, que a menudo no heredan fuentes por defecto en las hojas de estilo del navegador, a utilizar la tipografía circundante con font: inherit.
Esto le brinda dos vías distintas para acceder al valor de un padre. Herencia automática solo se aplica a las propiedades heredadas y únicamente cuando no existe un valor en cascada. Herencia explícita mediante inherit es en sí misma una declaración, por lo que prevalece sobre la cascada al igual que cualquier otro valor y funciona para cualquier propiedad.
Restablecimiento con initial
La palabra clave asociada es:
initial
Al aplicarse a una propiedad, restablece dicha propiedad a su valor inicial según lo define la especificación:
.child {
color: initial;
}
Tenga en cuenta que “initial” se refiere al valor predeterminado de la especificación, no a la hoja de estilo predeterminada del navegador ni al valor que un elemento heredaría de otro modo. Para color, el valor inicial es el color de texto del sistema (generalmente negro), por lo que color: initial no restaura el color del elemento padre; más bien lo separa de él. Para display, el valor inicial es inline, y por eso display: initial en un div lo convierte en estilo en línea en lugar de devolverlo al formato de bloque.
Junto a ellos, estas dos palabras clave realizan funciones opuestas:
inherit → use the parent's value
initial → reset to the property's initial value
Juntos le brindan un control explícito sobre cómo se transfieren los valores a través del árbol. CSS también ofrece unset (que se comporta como inherit para las propiedades heredadas y como initial para el resto) y revert (que vuelve a la hoja de estilo predeterminada del navegador); ambos suelen ser más útiles que initial para restablecer componentes.
Comprendiendo el panorama completo
Es útil ver la herencia junto con los pasos que la preceden. Cuando varias reglas apuntan al mismo elemento, el navegador comienza con la cascada, que compara las declaraciones en este orden:
Importance
↓
Specificity
↓
Source Order
El resultado es el valor en cascada. Este valor luego pasa por una secuencia de etapas de procesamiento hasta convertirse en algo que el diseño y la renderización puedan utilizar:
Declared Value
↓
Cascaded Value
↓
Specified Value
↓
Computed Value
↓
Used Value
↓
Actual Value
Cuando no existe un valor en cascada, la herencia proporciona el valor de entrada para esa secuencia:
No Cascaded Value
↓
Can Property Be Inherited?
↓
Yes
↓
Parent's Computed Value
↓
Child
En términos estrictos, la especificación sitúa la herencia en el punto en que se determina el valor especificado: el valor especificado es el valor en cascada si existe, de lo contrario es el valor calculado del padre para las propiedades heredadas, y en caso contrario es el valor inicial. A partir de ahí continúan las etapas habituales de cálculo, uso y valor real. Por lo tanto, una visión general simplificada de la etapa de procesamiento de CSS se ve así:
CSS
↓
Cascade
↓
┌─────────────┴─────────────┐
↓ ↓
Importance Specificity
↓
Source Order
↓
Cascaded Value
↓
Value Processing
↓
Computed / Used / Actual
↓
Inheritance
↓
CSSOM
Interprete el orden vertical en ese diagrama como un agrupamiento de conceptos y no como una línea de tiempo estricta, ya que la herencia proporciona el valor especificado en lugar de aplicarse después de los valores calculados. La idea clave es la misma en ambos casos: ocurren muchas más cosas entre la hoja de estilo y la pantalla que simplemente “escribí una regla y el navegador la aplicó”.
De la hoja de estilo a los píxeles
Si observamos el panorama general, aquí está el recorrido completo con la etapa CSS ampliada:
HTML
↓
DOM
↓
CSS
↓
Cascade
↓
Specificity
↓
Value Processing
↓
Inheritance
↓
CSSOM
↓
DOM + CSSOM
↓
Render Tree
↓
Layout
↓
Paint
↓
Pixels
Teniendo en cuenta ese proceso, incluso una regla sencilla implica mucho trabajo implícito:
.title {
font-size: 2rem;
color: blue;
}
Antes de dibujar cualquier cosa, el navegador debe determinar:
- qué declaraciones se aplican a cada elemento;
- cuál de ellas prevalece cuando hay conflictos;
- qué tan específicos son los selectores en competencia;
2rem en píxeles);Solo después de todo esto la página pasa a la etapa de maquetación y renderizado.
CSS como sistema en lugar de una lista de reglas
Gran parte de la confusión en torno a CSS desaparece una vez que dejas de tratarlo como reglas aisladas y comienzas a verlo como un sistema con responsabilidades claras:
- Especificidad explica por qué una declaración prevalece sobre otra.
- Orden de las fuentes resuelve los empates cuando la especificidad es igual.
- Procesamiento de valores convierte lo que escribiste en valores que el navegador puede utilizar.
- Herencia explica de dónde provienen los valores cuando no se ha especificado ninguno.
Juntos, convierten una hoja de estilos en un conjunto completo de valores finales que determinan el diseño y la representación visual. Incluso una declaración tan breve como esta:
width: 66%;
pasará por todos ellos. El navegador determina qué regla se aplica, procesa el porcentaje, lo relaciona con el bloque contenedor y establece un ancho final, todo antes de que aparezca siquiera un píxel.
Lo que queda después es otra cuestión distinta: dónde se colocará exactamente cada elemento. Los anchos, alturas, flujo normal, posicionamiento y el modelo de caja pertenecen al modelo de formato visual, la siguiente etapa del proceso, que toma estos valores finales y los convierte en un diseño concreto.
Puntos clave
- Una propiedad obtiene su valor primero de la cascada; solo se consulta la herencia cuando no hay ninguna declaración aplicable.
- Cada propiedad se define como heredada (en su mayoría relacionadas con texto:
color,font-*) o no heredada (en su mayoría relacionadas con el contenedor:margin,padding). - Los hijos heredan el valor calculado del padre, por lo que las alturas de línea en porcentaje o
emse transmiten como longitudes fijas; es preferible utilizarline-heightsin unidades. - Las propiedades no heredadas que no tienen declaración utilizan su valor inicial, como
0para el padding. inheritfuerza la herencia de cualquier propiedad;initialrestablece al valor por defecto de la especificación, no al del padre;unsetyrevertsuelen ser las herramientas de restablecimiento más adecuadas.
Lecturas relacionadas
- Nueve técnicas de modo oscuro comparadas, desde trucos con filtros hasta cookies del servidor — Compare nueve formas de agregar modo oscuro a una aplicación web, desde filtros invertidos hasta tokens, light-dark() y cookies del servidor, y descubra qué errores introduce silenciosamente cada una de ellas.
- Reflow, Repaint, Composite: Qué cuesta al navegador cada cambio en CSS — Siga el proceso de HTML y CSS a través del DOM, CSSOM, el diseño, la pintura y la composición, y entienda por qué los cambios de ancho cuestan más que los cambios de color y cómo evitar problemas en el diseño.