Saltar al contenido
cascada-y-herencia.css · devschool

Cascada y especificidad en CSS

Lección 3 de 25 · 5 min de lectura · Actualizado el

En esta lección
  1. 1. La cascada: de dónde viene la regla
  2. 2. La especificidad: qué selector es más concreto
  3. 3. El orden: a igual especificidad, gana la última
  4. !important: el último recurso
  5. La herencia
  6. Cómo averiguar qué regla gana
  7. Resumen

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:

  1. El navegador: sus estilos por defecto (por eso un <h1> sale grande y en negrita sin que hagas nada).
  2. El usuario: preferencias propias, como un tamaño de letra mayor.
  3. 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:

ColumnaQué cuentaEjemplo
ANúmero de id#menu
BNúmero de clases, atributos y pseudoclases.activo, [type="text"], :hover
CNúmero de etiquetas y pseudoelementosli, a, ::before

El resultado se escribe como tres números (A, B, C) y se compara de izquierda a derecha, como un marcador:

SelectorEspecificidad
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 en color: inherit para 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 como inherit si la propiedad se hereda y como initial si 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:

  1. ¿Alguna declaración tiene !important?
  2. ¿Qué regla tiene el selector más específico?
  3. A igual especificidad, ¿cuál está más abajo?
  4. 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).

cascada-y-herencia.html
Resultado

Pon a prueba lo que has aprendido

[CSS] ¿De qué color es el párrafo?
<p id="intro" class="texto">Hola</p>

#intro { color: red; }
.texto { color: blue; }
p { color: green; }

[CSS] ¿Qué selector es más específico?

[CSS] ¿Cuál de estas propiedades se hereda?

[CSS] Dos reglas con la misma especificidad dan distinto color a un elemento. ¿Cuál gana?

¿Te ha quedado claro? Márcala y verás tu progreso en el explorador.