O que é a especificidade?
Aqui está a outra metade do mistério "por que meu CSS não se aplica?". Quando duas
regras de mesma origem colidem, não vence a última pura e simplesmente: vence
a de maior especificidade, uma medida do peso do seletor. Ela é calculada
contando três categorias, que você pode imaginar como um número de três colunas
(A, B, C):
| Categoria | Conta | Peso |
|---|---|---|
id (#cabecalho) |
nº de ids | 100 |
classe / atributo / pseudo-classe (.aviso, [type], :hover) |
nº deles | 10 |
elemento / pseudo-elemento (div, ::before) |
nº deles | 1 |
O seletor universal
*e os combinadores (,>,+,~) não contribuem com especificidade.
Exemplos comparados
/* especificidade 0,0,1 → 1 */
p { color: black; }
/* especificidade 0,1,1 → 11 */
p.destacado { color: green; }
/* especificidade 0,1,0 → 10 */
.destacado { color: blue; }
/* especificidade 1,0,0 → 100 */
#aviso { color: red; }
Sobre um <p class="destacado" id="aviso">, venceria #aviso (100) porque o
id pesa mais que qualquer combinação de classes ou elementos. E entre
p.destacado (11) e .destacado (10), vence p.destacado por ser mais
específico, ainda que .destacado seja declarado depois.
A comparação é categoria a categoria, da esquerda para a direita: um único id
vence qualquer número de classes, e uma única classe vence qualquer número de
elementos. Por isso 10 classes (0,10,0) não superam um id (1,0,0).
⚠️ CILADA CLÁSSICA: id passa por cima de classe, e classe passa por cima de
tag, não importa a ordem. Imagine um menu com .link { color: gray } para o
estado normal e #menu a { color: tomato } para destacar: o id manda e os links
saem laranja, mesmo a classe estando escrita depois. Não é mágica nem falha do
navegador; é a coluna da esquerda mandando sobre a da direita. Quando uma regra
"não funciona", a primeira coisa a se perguntar é qual outra a está superando em
especificidade.
!important: o último recurso
Adicionar !important a uma declaração a tira da competição normal de
especificidade e a coloca acima:
.botao { color: blue !important; }
#cabecalho .botao { color: red; } /* perde: o !important vence */
Funciona, e é justamente por isso que vicia: quando algo "não se aplica", jogar um
!important resolve na hora. O problema é que é solução de curto prazo que cobra
caro depois, uma má prática, exceto em casos muito pontuais:
- Quebra a cascata natural e torna o CSS difícil de prever.
- Para sobrescrever um
!importantvocê precisa de outro!importantainda mais específico: começa uma guerra de!importantsem fim. - Quase sempre é sintoma de um problema de especificidade mal resolvido, tapado em vez de resolvido.
A boa prática é manter a especificidade baixa e uniforme (apoie-se em
classes, evite os ids para estilizar e não aninhe seletores em excesso). Assim a
cascata e a ordem de aparição bastam para que a regra correta vença, e o
!important fica onde deve: como último recurso, não como seu martelo para
tudo.