Especificidade

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 ID
  • B: especificidade semelhante a uma classe
  • C: 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.

Um diagrama mostrando os três componentes de especificidade (A,B,C). Para cada componente, o diagrama mostra o que ele representa e alguns exemplos de seletores que o afetam.
Um diagrama que demonstra qual componente de especificidade é afetado por vários seletores.

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)
O a tem valor (0,0,1), mas o [href="#"] tem valor (0,1,0).
(0,1,0)
Tente novamente. O a tem valor (0,0,1), mas o [href="#"] tem valor (0,1,0).
(0,1,1)
O 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
Os elementos adicionam especificidade semelhante a elementos (componente "C"). Há dois elementos no seletor, o que faz com que ele tenha uma especificidade de (0,0,2).
article.card.dark
Os elementos adicionam especificidade semelhante a um elemento (componente "C"), e as classes adicionam especificidade semelhante a uma classe (componente "B"). Com duas classes e um elemento, esse seletor tem uma especificidade de (0,2,1).
article:hover a[href]
Os elementos adicionam especificidade semelhante a elementos (componente "C"), e as pseudoclasses e os atributos adicionam especificidade semelhante a classes (componente "B"). Há dois seletores de elementos (2 × (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.

Recursos