¿Qué es la especificidad?
Aquí está la otra mitad del misterio "¿por qué mi CSS no se aplica?". Cuando dos
reglas de igual origen chocan, no gana la última sin más: gana la de mayor
especificidad, una medida del peso del selector. Se calcula contando tres
categorías, que puedes imaginar como un número de tres columnas (A, B, C):
| Categoría | Cuenta | Peso |
|---|---|---|
id (#cabecera) |
nº de ids | 100 |
clase / atributo / pseudo-clase (.aviso, [type], :hover) |
nº de ellos | 10 |
elemento / pseudo-elemento (div, ::before) |
nº de ellos | 1 |
El selector universal
*y los combinadores (,>,+,~) no aportan especificidad.
Ejemplos comparados
/* especificidad 0,0,1 → 1 */
p { color: black; }
/* especificidad 0,1,1 → 11 */
p.destacado { color: green; }
/* especificidad 0,1,0 → 10 */
.destacado { color: blue; }
/* especificidad 1,0,0 → 100 */
#aviso { color: red; }
Sobre un <p class="destacado" id="aviso">, ganaría #aviso (100) porque el
id pesa más que cualquier combinación de clases o elementos. Y entre
p.destacado (11) y .destacado (10), gana p.destacado por ser más
específico, aunque .destacado se declare después.
La comparación es categoría a categoría, de izquierda a derecha: una sola id
vence a cualquier número de clases, y una sola clase vence a cualquier número de
elementos. Por eso 10 clases (0,10,0) no superan a un id (1,0,0).
⚠️ TRAMPA CLÁSICA: id pisa a clase, y clase pisa a etiqueta, sin importar el
orden. Imagina un menú con .enlace { color: gray } para el estado normal y
#menu a { color: tomato } para resaltarlo: el id manda y los enlaces salen
naranjas, aunque la clase esté escrita después. No es magia ni un fallo del
navegador; es la columna de la izquierda mandando sobre la de la derecha. Cuando
una regla "no funciona", lo primero que debes preguntarte es qué otra la supera en
especificidad.
!important: el último recurso
Añadir !important a una declaración la saca de la competición normal de
especificidad y la coloca por encima:
.boton { color: blue !important; }
#cabecera .boton { color: red; } /* pierde: el !important gana */
Funciona, y por eso engancha: cuando algo "no se aplica", soltar un !important
lo arregla al instante. El problema es que es pan para hoy y hambre para mañana,
una mala práctica salvo casos muy puntuales:
- Rompe la cascada natural y hace el CSS difícil de predecir.
- Para sobrescribir un
!importantnecesitas otro!importantaún más específico: empieza una guerra de!importantsin fin. - Casi siempre es síntoma de un problema de especificidad mal resuelto, tapado en lugar de resuelto.
La buena práctica es mantener la especificidad baja y uniforme (apóyate en
clases, evita los ids para estilar y no anides selectores en exceso). Así la
cascada y el orden de aparición bastan para que gane la regla correcta, y el
!important se queda donde debe: como último recurso, no como tu martillo para
todo.