Curso de CSS / herencia, especificidad y cascada
La cascada elige entre declaraciones CSS en competencia, mientras que la especificidad compara la fuerza de los selectores dentro de las condiciones relevantes de la cascada. La herencia proporciona ciertos valores de un elemento padre cuando ninguna declaración aplicable los determina; estos son mecanismos relacionados pero diferentes.
Distingue la herencia de las declaraciones directas
La herencia ocurre cuando un elemento hijo hereda el valor de su elemento padre. Mientras que las propiedades relacionadas con el color del texto y la fuente generalmente se heredan, el borde y el relleno no se heredan por defecto. Si asumes que todas las propiedades serán iguales a las de su padre, podrías esperar bordes que en realidad no se transmiten a los párrafos.
#main {
color: purple;
border: 1px solid purple;
}
p { color: #555; }
<main id="main">
<h1>Small Garden</h1>
<p>Visitor information.</p>
</main>
Suponiendo que solo apliquemos estas dos piezas, h1 heredará el color púrpura de su padre main. El color gris que especificas se aplica a p. El hecho de que #main del padre sea un selector de ID, no anula la asignación directa del hijo p. Esto se debe a que no es una competencia entre dos selectores que se aplican al mismo elemento. El borde se crea alrededor de la caja de main y no se duplica por los bordes de h1 y p respectivamente.
Las propiedades no heredadas también pueden heredar el valor calculado del padre especificándolo como border: inherit. Si una declaración válida determina directamente la propiedad del hijo, ese valor prevalece sobre la herencia predeterminada, aunque la propiedad sea heredable. Puedes averiguar qué propiedades se heredan y qué significa heredar en la descripción de herencia de CSS de MDN .
Sigue el proceso de decisión de la cascada
Comienza con el CSS ordinario del autor, como las reglas que escribes para esta página. Antes de comparar declaraciones, verifica que el selector coincida, que la sintaxis sea válida y que se cumplan condiciones como las consultas de medios. Excluye reglas que no coincidan y declaraciones inválidas de la comparación.
- Comprueba primero el origen, la importancia y la capa. Las fuentes CSS del autor y CSS del usuario/estilo predeterminado del navegador, si es !important, si se utiliza @layer, etc., son relevantes aquí. Si las condiciones principales son diferentes, la decisión no se toma comparando solo los puntajes del selector.
- Compara la especificidad del selector dentro de las mismas condiciones. La prioridad (especificidad) es un criterio para comparar cuán específico es un selector. Compara ID, clases y equivalentes, y tipos de elemento en ese orden.
- Si la prioridad es la misma, se usa la declaración escrita más tarde. En situaciones donde no hay condiciones adicionales como @scope, como en los ejemplos de esta lección, los empates finales se resuelven en el orden de la fuente.
- Para cada propiedad, CSS resuelve las declaraciones aplicables y luego realiza la asignación de valores predeterminados cuando es necesario. Las propiedades heredables pueden obtener un valor del padre; otras propiedades normalmente usan su valor inicial. Esto no significa que cada declaración en una regla ganadora reemplaza toda una regla anterior.
La cascada es el proceso completo de resolución de conflictos de CSS; la especificidad del selector es un criterio dentro de él. Las animaciones, transiciones, capas y ámbitos introducen reglas adicionales, por lo que los ejemplos simples aquí no representan todos los casos. Las reglas de ordenación de la cascada del W3C definen las relaciones entre origen, importancia y capas. El ejemplo completo que se muestra a continuación no utiliza animaciones, transiciones, @layer ni @scope. El artículo Organizar CSS con Estilos Compartidos, Anidamiento y Capas demuestra cómo agrupar reglas en capas.
Compara la especificidad en tres columnas
El selector básico en esta lección se puede leer en tres columnas: número de IDs, número de clases/atributos/pseudoclases y número de elementos/pseudoelementos. Compara desde la columna izquierda y, si hay una diferencia, decide según el resultado. No lo memorices simplemente como una tabla de puntuación decimal sumando ID=100, clase=10, elemento=1. El hecho de que haya muchas clases no significa que supere la columna de ID.
| selector | ID | Clase, atributo, pseudo-clase | Elemento/Pseudo-elemento | notación |
|---|---|---|---|---|
p |
0 | 0 | 1 | 0-0-1 |
.notice |
0 | 1 | 0 | 0-1-0 |
p.notice |
0 | 1 | 1 | 0-1-1 |
[required] |
0 | 1 | 0 | 0-1-0 |
a:hover |
0 | 1 | 1 | 0-1-1 |
p::before |
0 | 0 | 2 | 0-0-2 |
#opening |
1 | 0 | 0 | 1-0-0 |
#main .notice |
1 | 1 | 0 | 1-1-0 |
p.notice y .notice tienen la misma columna ID y la misma columna de clase. Hay una diferencia entre 1 y 0 en la columna de elementos, por lo que p.notice tiene mayor especificidad. #opening y p.notice tienen una diferencia de 1 y 0 en la primera columna, por lo que #opening tiene mayor especificidad. Los espacios en blanco, las notaciones relacionales como >, +, ~ y el selector universal * no aumentan directamente el número de estas comparaciones.
p.notice { color: #087f5b; }
.notice { color: tomato; }
Bajo las mismas condiciones de origen, importancia y capa, p.notice tiene mayor especificidad que .notice, por lo que su color verde prevalece incluso cuando aparece antes. Los selectores idénticos tienen la misma especificidad, permitiendo que el orden en el código determine un empate. Algunas pseudoclases funcionales tienen reglas adicionales de especificidad. Véase MDN: Specificity.
Resuelve cada propiedad por separado
.notice {
color: blue;
padding: 12px;
border: 1px solid #087f5b;
}
.notice {
color: tomato;
padding: 20px;
}
Si solo se aplican estas dos reglas al mismo elemento, color y padding usan la declaración de la última, y el borde de la regla anterior se mantiene. El hecho de que no haya border en la regla siguiente no significa que toda la regla anterior desaparezca. CSS debe entenderse como “determinar valores para cada propiedad” en lugar de “seleccionar un bloque de regla completo”.
Por ejemplo, el color del texto puede provenir de una regla de ID, el margen puede provenir de una regla de clase posterior, y el borde puede provenir de una regla de clase anterior. Incluso cuando ves el tachado en las herramientas de desarrollo, lee las declaraciones una por una. Que el color tenga un tachado no significa que el padding del mismo bloque no se aplique.
Predice el ejemplo completo antes de ejecutarlo
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Small Garden</title>
<style>
body { margin: 24px; font-family: sans-serif; line-height: 1.7; }
#main { color: purple; }
p { color: #555; }
.notice {
color: blue;
padding: 12px;
border: 1px solid #087f5b;
}
p.notice { color: #087f5b; }
.notice { color: tomato; padding: 20px; }
#opening { color: #1d4ed8; }
</style>
</head>
<body>
<main id="main">
<h1>Small Garden</h1>
<p id="opening" class="notice">A: We open at 9am every day.</p>
<p class="notice">B: Prepare a water bottle and comfortable shoes.</p>
<p>C: Please inquire at the information desk.</p>
</main>
</body>
</html>
Predice los colores de A·B·C y el relleno del aviso antes de abrirlo en tu navegador. Si guardas todo el código como index.html y lo abres, obtendrás el siguiente resultado. La fuente del body y la altura de línea son configuraciones auxiliares para una visualización más fácil.
| objeto y propiedades | resultado final | Razón de la decisión |
|---|---|---|
| color de h1 | Morado | Hereda el color de main. No hay otras declaraciones de color en h1. |
| color de A | Azul #1d4ed8 | #opening tiene mayor especificidad que p.notice, .notice, p aplicado al mismo A. |
| color de B | Verde #087f5b | p.notice tiene mayor especificidad que la regla .notice posterior. |
| color de C | Gris #555 | Usa un valor directo para p y no hereda el color morado del padre. |
| relleno de A·B | 20px | Las dos declaraciones .notice tienen la misma especificidad, por lo que el relleno del segundo es el que prevalece. |
| borde de A·B | línea sólida verde de 1px | Dado que no hay una declaración de borde en la regla posterior, la declaración válida anterior permanece. |
Al comprobar en Computed, el color de A puede mostrarse como rgb(29, 78, 216), el color de B puede mostrarse como rgb(8, 127, 91) y el color de C puede mostrarse como rgb(85, 85, 85). Incluso si la notación del color es diferente, indica el mismo valor. Verifica que el relleno sea de 20px en cada dirección y que el grosor y la forma de la línea del borde sean los mismos.
Compara !important y estilos en línea
!important es una notación que cambia la importancia de una declaración. No es una función que agregue un número grande a las tres columnas del selector. Según la fuente del mismo autor, las declaraciones importantes tienen prioridad sobre las declaraciones normales, por lo que agregar la regla a continuación al final de todo el ejemplo cambiará el color de A y B a tomato, un rojo anaranjado. La declaración de color simple en ID tampoco tiene prioridad sobre esta declaración importante.
.notice { color: tomato !important; }
Este resultado no significa que important siempre sea más fuerte que todos los estilos. Los estilos importantes del usuario, los valores durante las transiciones, etc., siguen un orden separado. Incluso entre declaraciones importantes, primero debes verificar el origen y la capa. En este ejercicio, observa important y luego elimina la regla que agregaste. Usualmente, es mejor para el mantenimiento organizar primero el rango de selección y la estructura.
<p class="notice" style="color: purple;">B: Information on what to prepare</p>
En el ejemplo original donde se eliminó la regla importante, si colocas un color en línea en B como se muestra arriba, tendrá prioridad sobre las reglas normales de la hoja de estilo y B se volverá morado. Los estilos en línea se tratan por separado de las tres columnas de selectores predeterminadas en la tabla de arriba. Nuevamente, poner importante en la regla de la clase general permite que tenga prioridad sobre el color regular en línea. Por lo tanto, “si es en línea, es incondicionalmente el más fuerte” también es una explicación sin condiciones.
Practica diagnosticar conflictos
- En el ejemplo completo original, mueve la regla
p.noticeal final. Asegúrate de que B siga siendo verde y que A conserve el color azul de su ID. En estados con alta especificidad, no serán anulados simplemente cambiando su orden. - A continuación, cambia solo el selector p.notice a
.noticey colócalo al final. El color de B usa el verde especificado por el último .notice. Dado que tenemos el mismo selector, el orden es ahora el criterio de decisión. Después de la confirmación, restaura el original. - Solo elimina
id="opening"de A. Comprueba si A se vuelve del mismo verde que B. Aunque el ID del padre main permanezca igual, no supera el color verde asignado directamente a A. Después de comprobarlo, restaura el ID de A. - En pasos separados, aplica los ejemplos importantes y en línea mencionados anteriormente uno por uno y compáralos. Restaura el ejemplo original antes de probar cada alternativa para que una regla del ejercicio anterior no altere el resultado.
Si el resultado difiere de tu expectativa, Inspecciona CSS con DevTools: Estilos y Computed. Selecciona el elemento correcto, encuentra las declaraciones para la propiedad, compara su importancia, selectores y orden, y luego inspecciona el valor final. Agregar IDs o !important sin encontrar la causa puede cambiar el color ahora mientras hace más difíciles las ediciones posteriores.




