Cascada y especificidad en CSS
En esta lección
A un mismo elemento le pueden llegar varias reglas que dicen cosas distintas. ¿De qué color es este párrafo?
<p id="intro" class="texto">Hola</p>
p { color: green; }
.texto { color: blue; }
#intro { color: red; }
Es rojo. Para entender por qué, hay que conocer tres mecanismos: la cascada, la especificidad y la herencia.
1. La cascada: de dónde viene la regla
Las reglas pueden venir de tres sitios:
- El navegador: sus estilos por defecto (por eso un
<h1>sale grande y en negrita sin que hagas nada). - El usuario: preferencias propias, como un tamaño de letra mayor.
- El autor: tú, con tus hojas de estilos.
Tus reglas ganan a las del navegador. Por eso, al empezar un proyecto, muchas personas usan un pequeño reset para partir de valores predecibles:
*, *::before, *::after { box-sizing: border-box; }
body { margin: 0; }
img { max-width: 100%; display: block; }
2. La especificidad: qué selector es más concreto
Cuando dos reglas tuyas chocan, gana la del selector más específico. Cada selector tiene un “peso” que se calcula contando tres tipos de piezas:
| Columna | Qué cuenta | Ejemplo |
|---|---|---|
| A | Número de id | #menu |
| B | Número de clases, atributos y pseudoclases | .activo, [type="text"], :hover |
| C | Número de etiquetas y pseudoelementos | li, a, ::before |
El resultado se escribe como tres números (A, B, C) y se compara de izquierda a derecha, como un marcador:
| Selector | Especificidad |
|---|---|
p | (0, 0, 1) |
ul li a | (0, 0, 3) |
.texto | (0, 1, 0) |
p.texto | (0, 1, 1) |
.menu a:hover | (0, 2, 1) |
#intro | (1, 0, 0) |
#menu .activo a | (1, 1, 1) |
Una sola clase gana a cualquier número de etiquetas: (0, 1, 0) es mayor que (0, 0, 11). Y un solo id gana a cualquier número de clases.
El selector universal * y los combinadores (espacio, >, +, ~) no suman nada.
Estilos en el atributo style
El CSS escrito en el atributo style de una etiqueta gana a cualquier selector de tu hoja de estilos. Es una de las razones para evitarlo.
3. El orden: a igual especificidad, gana la última
Si dos reglas tienen la misma especificidad, gana la que aparece más abajo en el CSS (o en el último archivo cargado):
.boton { background: blue; }
.boton { background: green; } /* gana esta */
Por eso importa el orden en que enlazas los archivos: si cargas tu CSS después del de una librería como Bootstrap, tus reglas ganan a las suyas cuando tienen la misma especificidad.
!important: el último recurso
.aviso { color: red !important; }
!important hace que esa declaración gane a todas las demás normales, sin importar la especificidad. Parece cómodo, pero rompe la lógica de la cascada: la única forma de ganarle es con otro !important, y en poco tiempo el CSS se convierte en una guerra.
Úsalo solo para clases de utilidad muy concretas (como .oculto { display: none !important; }) o para sobrescribir CSS de terceros que no puedes cambiar. Si lo necesitas a menudo, es señal de que tus selectores son demasiado específicos.
La herencia
Algunas propiedades se heredan: si se las das a un elemento, las reciben también todos sus descendientes, salvo que estos digan otra cosa.
body {
font-family: system-ui, sans-serif;
color: #1b2d34;
}
Con esta regla, todos los párrafos, títulos, listas y enlaces de la página usan esa fuente y ese color sin escribirlo en cada uno.
- Se heredan casi todas las propiedades de texto:
color,font-family,font-size,font-weight,line-height,text-align,letter-spacing,list-style,visibility,cursor. - No se heredan las de caja y posición:
margin,padding,border,background,width,height,display,position. Tendría poco sentido que cada párrafo de una tarjeta tuviera el mismo borde que la tarjeta.
Un valor que pones directamente en un elemento siempre gana al heredado, aunque el heredado venga de un selector muy específico:
#contenido { color: red; }
p { color: black; } /* los <p> dentro de #contenido son negros */
Valores especiales
Cualquier propiedad acepta estos valores:
inherit: hereda el valor del padre, aunque la propiedad normalmente no se herede. Muy útil encolor: inheritpara que un enlace tenga el color del texto que lo rodea.initial: vuelve al valor inicial definido por CSS para esa propiedad.unset: se comporta comoinheritsi la propiedad se hereda y comoinitialsi no.
.tarjeta a { color: inherit; text-decoration: none; }
Cómo averiguar qué regla gana
En el inspector (F12 → Elementos), el panel Estilos muestra todas las reglas que afectan al elemento, ordenadas de mayor a menor prioridad. Las declaraciones que han perdido aparecen tachadas. En la pestaña Calculado (Computed) ves el valor final de cada propiedad y de qué regla viene.
Resumen
Para decidir el valor de una propiedad, CSS mira, por este orden:
- ¿Alguna declaración tiene
!important? - ¿Qué regla tiene el selector más específico?
- A igual especificidad, ¿cuál está más abajo?
- Si ninguna regla le da valor, ¿la propiedad se hereda? Si sí, toma el del padre; si no, su valor inicial.
Pruébalo tú
Cambia el código y pulsa Ejecutar (o Ctrl + Enter).
Pon a prueba lo que has aprendido
¿Te ha quedado claro? Márcala y verás tu progreso en el explorador.