O podcast do CSS - 003: Especificidade
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. 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 tenta colorir 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 abordada no último módulo, sobre a 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 a especificidade em um projeto real, o equilíbrio é garantir que as regras de CSS que você espera aplicar sejam aplicadas , mantendo as pontuações baixas para evitar complexidade. A especificidade só deve ser tão alta quanto precisamos, em vez de buscar a maior especificidade possível. No futuro, alguns CSSs genuinamente mais importantes podem precisar ser aplicados. Se você buscar a maior especificidade, vai dificultar esse 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 classeC: especificidade semelhante a elemento
Geralmente, ela é representada 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.
Como comparar 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) é considerada uma especificidade maior 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 da 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 pseudo-elemento
Um elemento (tipo)
ou pseudo-elemento
seletor adiciona especificidade semelhante a elemento que incrementa o componente C em 1.
Os exemplos a seguir têm uma especificidade geral de (0,0,1).
Seletor de tipo
div {
color: red;
}
Seletor de pseudo-elemento
::selection {
color: red;
}
Seletor de classe, pseudo-classe ou atributo
Um seletor de classe,
pseudo-classe ou
atributo adiciona especificidade semelhante a classe
que incrementa o componente B em 1.
Os exemplos a seguir têm uma especificidade de (0,1,0).
Seletor de classe
.my-class {
color: red;
}
Seletor de pseudo-classe
:hover {
color: red;
}
Seletor de atributo
[href='#'] {
color: red;
}
Seletor de ID
Um seletor
de ID adiciona especificidade semelhante a ID, que incrementa o componente A 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 adicionam especificidade.
Por exemplo, a :not() pseudo-classe
não adiciona nada ao cálculo de especificidade.
A especificidade da pseudo-classe :not() é substituída pela especificidade do seletor mais específico no argumento de seletores separados por vírgulas, fornecendo a mesma especificidade como se tivesse sido escrita :not(:is(argument)).
div:not(.my-class) {
color: red;
}
A :is() pseudo-classe
também não adiciona ao cálculo de especificidade. Como :not(), ela usa a especificidade do argumento mais específico.
:is(h1, h2, h3) {
color: blue;
}
Este exemplo tem uma especificidade de (0,0,1) porque tem apenas um tipo de seletor (type).
Com a adição de um id, a especificidade aumenta para (1,0,0).
:is(h1, h2, h3, #my-heading) {
color: blue;
}
A :where() pseudo-classe
é diferente. Não importa a especificidade de qualquer um dos argumentos, ela sempre tem uma especificidade de (0,0,0).
:where(h1, h2, h3, #my-heading) {
color: blue;
}
Os estilos de baixa especificidade aplicados usando :where() permitem substituir esses estilos com seletores básicos mais tarde na sua folha de estilo:
:where(#my-content) {
color: red;
}
p {
color: blue;
}
Mesmo que :where() tenha um id na lista de argumentos, ele ainda tem apenas uma especificidade de (0, 0, 0), então o seletor p básico o substitui e o texto será blue.
Teste seu conhecimento
Teste seu conhecimento sobre a pontuação de especificidade
Qual é a especificidade de a[href=/learn/css/%22#%22%5D%3C%2Fcode>?
(0,0,1)a vale (0,0,1), mas o [href=/learn/css/%22#%22%5D%3C%2Fcode> vale (0,1,0).(0,1,0)a vale (0,0,1), mas o [href=/learn/css/%22#%22%5D%3C%2Fcode> vale (0,1,0).(0,1,1)a vale (0,0,1) e o [href=/learn/css/%22#%22%5D%3C%2Fcode> vale (0,1,0), 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 seguintes fatores que afetam a especificidade.
Atributos de estilo in-line
O CSS aplicado diretamente ao atributo style de um elemento,
não afeta a especificidade, já que é uma etapa diferente em cascata
que é avaliada antes da especificidade.
<div style="color: red"></div>
Para substituir essa declaração em uma folha de estilo, é necessário recorrer para que a declaração vença em uma etapa anterior de cascata.
Por exemplo, você pode adicionar !important a ela,
para que ela se torne parte da origem !important criada.
Declarações !important
Um !important no final de uma declaração CSS não afeta a especificidade
mas coloca a declaração em uma origem diferente origem,
ou seja, Authored !important.
No exemplo a seguir, 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 é adicionada à 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ê referenciar uma das classes no seletor,
ela agora 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 :hover pseudo-classe 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 seu conhecimento 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 atributo (que vale (0,1,0)) e um seletor de classe (que vale (0,1,0)). Isso faz com que esse seletor tenha uma especificidade total de (0,2,2).Aumentar a especificidade de forma pragmática
Suponha que você tenha um CSS como este:
.my-button {
background: blue;
}
button[onclick] {
background: grey;
}
Com HTML como 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 que (0,1,1).
Se você quiser dar um impulso a essa regra, repita o seletor de classe desta forma:
.my-button.my-button {
background: blue;
}
button[onclick] {
background: grey;
}
Agora, o botão terá um plano de fundo azul, porque o novo seletor tem uma especificidade (0,2,0)
Um empate na especificidade volta para a próxima etapa na cascata
Continuando com o exemplo de botão por enquanto, mude o CSS para este:
.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 as regras na ordem de origem, o botão ficará azul.
[onclick] {
background: grey;
}
.my-button {
background: blue;
}
Isso ocorre porque ambos os seletores têm a mesma especificidade. Nesse caso, a cascata volta para a etapa de ordem de aparência.