The CSS Podcast - 003: Specificity (em inglês)
Suponha que você esteja trabalhando com o seguinte HTML e CSS:
<button class="branding">Hello, Specificity!</button>
.branding {
color: blue;
}
button {
color: red;
}
Há duas regras que segmentam o mesmo elemento aqui. Cada regra contém uma declaração que quer definir a cor do botão: uma tenta colorir o botão de vermelho, e a outra, de azul. Qual declaração é aplicada ao elemento?
Entender o algoritmo de especificidade do CSS é fundamental para entender como o CSS decide entre declarações concorrentes.
A especificidade é um dos estágios distintos da cascata, que foi abordado no último módulo, na cascata.
Pontuação de especificidade
Cada regra de seletor em uma origem recebe uma pontuação. Você pode pensar na especificidade como uma pontuação total, e cada tipo de seletor ganha pontos para essa pontuação. As declarações de regras com a maior especificidade vencem.
Com especificidade em um projeto real, o equilíbrio é garantir que as regras CSS que você espera aplicar se apliquem, mantendo as pontuações baixas para evitar a complexidade. A especificidade precisa ser tão alta quanto necessário, em vez de buscar a maior especificidade possível. No futuro, talvez seja necessário aplicar alguns CSS mais importantes. Se você optar pela maior especificidade, vai dificultar o trabalho.
A especificidade não é um número decimal, mas uma tríade
que consiste em três componentes: A
, B
e C
.
A
: especificidade semelhante a IDB
: especificidade semelhante a uma classeC
: especificidade semelhante a um elemento
Ele é representado com frequência usando a notação (A,B,C)
. Por exemplo, (1,0,2)
.
A notação alternativa A-B-C
também é usada com frequência.
Comparação de especificidades
As especificidades são comparadas comparando os três componentes em ordem: a especificidade com um valor A maior é mais específica; se os dois valores A estiverem empatados, a especificidade com um valor B maior será mais específica; se os dois valores B também estiverem empatados, a especificidade com um valor C maior será mais específica; se todos os valores estiverem empatados, as duas especificidades serão iguais.
Por exemplo, (1,0,0)
é considerado mais específico que (0,4,3)
porque o valor A
em (1,0,0)
(que é 1
)
é maior que o valor A
de (0,4,3)
(que é 0
).
Os seletores influenciam a especificidade
Cada parte na tríade de especificidade começa com um valor de 0
,
então a especificidade padrão é (0,0,0)
.
Cada parte de um seletor aumenta a especificidade que, dependendo do tipo de seletor,
incrementa o valor de A
, B
ou C
.
Seletor universal
Um seletor universal (*
)
não adiciona especificidade, deixando o valor na especificidade inicial de (0,0,0)
.
* {
color: red;
}
Seletor de elemento ou pseudoelemento
Um seletor de elemento (tipo)
ou pseudoelemento
adiciona especificidade semelhante a um elemento, que incrementa o componente C
por 1
.
Os exemplos a seguir têm uma especificidade geral de (0,0,1)
.
Seletor de tipo
div {
color: red;
}
Seletor de pseudoelementos
::selection {
color: red;
}
Seletor de classe, pseudoclasse ou atributo
Um seletor de classe,
pseudoclasse ou
atributo adiciona uma especificidade semelhante à classe
que incrementa o componente B
por 1
.
Os exemplos a seguir têm uma especificidade de (0,1,0)
.
Seletor de classe
.my-class {
color: red;
}
Seletor de pseudoclasse
:hover {
color: red;
}
Seletor de atributo
[href='#'] {
color: red;
}
Seletor de ID
Um seletor de ID
adiciona uma especificidade semelhante a ID que incrementa o componente C
em 1,
desde que você use um seletor de ID (#myID
) e não um seletor de atributo ([id="myID"]
).
No exemplo a seguir, a especificidade é (1,0,0)
#myID {
color: red;
}
Outros seletores
O CSS tem muitos seletores. Nem todos eles são específicos.
Por exemplo, a pseudoclasse :not()
não adiciona nada ao cálculo de especificidade.
No entanto, os seletores transmitidos como argumentos são adicionados ao cálculo de especificidade.
div:not(.my-class) {
color: red;
}
Esse exemplo tem uma especificidade de (0,1,1)
porque tem um seletor de tipo (div
) e uma classe dentro do :not()
.
Teste seu conhecimento
Teste seus conhecimentos sobre a pontuação de especificidade
Qual é a especificidade de a[href="#"]
?
(0,0,1)
a
tem valor (0,0,1)
, mas o [href="#"]
tem valor (0,1,0)
.(0,1,0)
a
tem valor (0,0,1)
, mas o [href="#"]
tem valor (0,1,0)
.(0,1,1)
a
tem valor (0,0,1)
e o [href="#"]
tem valor (0,1,1)
, o que resulta em uma especificidade total de (0,1,1)
.Fatores que não afetam a especificidade
Há alguns equívocos comuns sobre os fatores a seguir que afetam a especificidade.
Atributos de estilo in-line
O CSS aplicado diretamente ao atributo style
de um elemento
não afeta a especificidade, porque é uma etapa diferente na cascata
que é avaliada antes da especificidade.
<div style="color: red"></div>
Para substituir essa declaração em uma folha de estilo, é necessário recorrer à vitória da declaração em uma etapa anterior da cascata.
Por exemplo, você pode adicionar !important
a ele,
para que ele se torne parte da origem !important
de autoria.
!important
declarações
Um !important
no final de uma declaração CSS não afeta a especificidade,
mas coloca a declaração em uma origem diferente,
ou seja, !important
de autoria.
No exemplo abaixo, a especificidade de .my-class
não é relevante para que a
declaração !important
vença.
.my-class {
color: red !important;
color: white;
}
Quando duas declarações são !important
, a especificidade entra em jogo novamente,
já que a etapa de origem da cascata ainda não conseguiu determinar o vencedor.
.branding {
color: blue !important;
}
button {
color: red !important;
}
Especificidade no contexto
Quando um seletor complexo ou composto é usado, cada parte desse seletor é somada à especificidade. Considere este exemplo de HTML:
<a class="my-class another-class" href="#">A link</a>
Esse link tem duas classes.
A regra no CSS a seguir tem uma especificidade de (0,0,1)
:
a {
color: red;
}
Se você fizer referência a uma das classes no seletor,
ele terá uma especificidade de (0,1,1)
:
a.my-class {
color: green;
}
Adicione a outra classe ao seletor.
Agora ela tem uma especificidade de (0,2,1)
:
a.my-class.another-class {
color: rebeccapurple;
}
Adicione o atributo href
ao seletor.
Agora ele tem uma especificidade de (0,3,1)
:
a.my-class.another-class[href] {
color: goldenrod;
}
Por fim, adicione uma pseudoclasse :hover
a tudo isso.
O seletor acaba com uma especificidade de (0,4,1)
:
a.my-class.another-class[href]:hover {
color: lightgrey;
}
Teste seu conhecimento
Teste seus conhecimentos sobre a pontuação de especificidade
Qual dos seguintes seletores tem uma especificidade de (0,2,1)
?
article > section
(0,0,2)
.article.card.dark
(0,2,1)
.article:hover a[href]
(0,0,1)
), um seletor de atributos ((0,0,1)
) e um seletor de classe ((0,0,1)
). Isso faz com que esse seletor tenha uma especificidade total de (0,2,2)
.Como aumentar pragmaticamente a especificidade
Digamos que você tenha um CSS parecido com este:
.my-button {
background: blue;
}
button[onclick] {
background: grey;
}
Com HTML parecido com este:
<button class="my-button" onclick="alert('hello')">Click me</button>
O botão tem um plano de fundo cinza,
porque o segundo seletor tem uma especificidade de (0,1,1)
.
Isso ocorre porque ele tem um seletor de tipo (button
),
que é (0,0,1)
, e um seletor de atributo ([onclick]
), que é (0,1,0)
.
A regra anterior (.my-button
) é igual a (0,1,0)
porque tem um seletor de classe, que é uma especificidade menor do que (0,1,1)
.
Se você quiser melhorar essa regra, repita o seletor de classe assim:
.my-button.my-button {
background: blue;
}
button[onclick] {
background: grey;
}
Agora, o botão terá um plano de fundo azul,
porque o novo seletor recebe uma especificidade (0,2,0)
.
Um empate na especificidade volta para a próxima etapa na cascata
Vamos ficar com o exemplo de botão por enquanto e mudar o CSS para:
.my-button {
background: blue;
}
[onclick] {
background: grey;
}
O botão tem um plano de fundo cinza
porque ambos os seletores têm uma especificidade idêntica de (0,1,0)
.
Se você mudar a ordem das regras, o botão vai ficar azul.
[onclick] {
background: grey;
}
.my-button {
background: blue;
}
Isso ocorre porque os dois seletores têm a mesma especificidade. Nesse caso, a cascata volta para a etapa de ordem de aparição.