Seletores e especificidade são assuntos basilares no CSS, portanto é um tema de estudo fundamental. Mas, o que significa especificidade? Olhando no dicionário, encontramos o seguinte:

Especificidade

s.f qualidade daquilo que é específico; particularidade; qualidade própria, peculiar, de uma espécie.

Definição por Oxford Languages

No contexto do CSS, a definição de especificidade não passa tão longe assim. Especificidade é o que define o quão especifico um seletor CSS é, portanto quanto mais específico, ele possui prioridade sob os outros.

Seletores

Primeiramente, vamos entender quais são os seletores mais específicos. Na lista abaixo, os seletores estão ordenados do mais específico ao menos específico.

  1. Ids #id { ... }
  2. Classes, atributos e pseudo-classes .classe { ... }
  3. Elementos e pseudo-elementos div { ... }

⚠️ Detalhe importante! Nessa publicação não vou me aprofundar no uso de atributos, pseudo-classes e pseudo-elementos, falarei disso em um artigo futuro.

Como calcular a especificidade?

O cálculo de especificidade é uma combinação desses três tipos de seletores, que gera algo mais ou menos assim:

(0, 0, 0)

Separadamente, esses números representam a quantidade de ids, classes e elementos usados na formação de um seletor CSS. O digito a esquerda terá maior prioridade que o da direita, ou seja, a primeira posição é a de maior peso, enquanto a terceira posição é a de menos peso. Então será feita uma comparação, de número a número, para decidir qual seletor possui maior especificidade (ou peso/prioridade).

Exemplo de cálculo de especificidade

Para ficar mais visível esse calculo, observe o trecho HTML abaixo:

<p id="id" class="classe">Hello World!</p>

E dado o seguinte trecho CSS:

#id {
    color: blue;
}

/*  Especificidade (0, 1, 0) */
.classe {
    color: red;
}

/*  Especificidade (0, 0, 1) */
p {
    color: green;
}

Antes de ver a resposta, tente descobrir qual será a cor aplicada ao elemento p. Qual o seletor que terá maior prioridade? O id, a classe ou o elemento?

A resposta certa é o id! Pois o digito mais a esquerda possui maior peso que o digito a direita!

Agora vamos aumentar o nível! Dado o trecho HTML abaixo:

<p id="id" class="classe1 classe2">Hello World!</p>

E agora, o seguinte trecho CSS:

/*  Especificidade (1, 0, 0) */
#id {
    color: blue;
}

/*  Especificidade (0, 2, 0) */
.classe1 .classe2 {
    color: red;
}

/*  Especificidade (0, 0, 1) */
p {
    color: green;
}

E agora? Quem possui maior especificidade? O id, a classe ou o elemento?

Mais uma vez, o id! Pelo mesmo motivo dito acima. Os digitos mais a esquerda possuem maior peso do que os digitos a direita. Ou seja, o 1 na primeira posição, possui muito mais peso do que o 2 na segunda posição.

(1, 0, 0) > (0, 2, 0)

O seletor de id sempre terá maior prioridade, então a única forma de superar um seletor de id é criando outro seletor de id mais específico. Como? Com o auxílio das outras duas posições. Veja:

/* (1, 0, 0) */
#id {
    color: blue;
}

/* (1, 2, 0)*/
#id.classe1.classe2 {
    color: red;
}

Logo:

(1, 2, 0) > (1, 0, 0)

Seguindo a mesma regra:

/* (1, 2, 0) */
#id.classe1.classe2 {
    color: blue;
}

/* (1, 2, 1)*/
#id.classe1.classe2 p {
    color: red;
}

Podemos ver que:

(1, 2, 1) > (1, 2, 0)

Veja mais alguns exemplos de cálculos de especificidade:

(0, 2, 0) > (0, 0, 20)
(1, 7, 0) > (0, 5, 0)
(1, 7, 0) > (1, 5, 3)
(1, 7, 3) > (1, 7, 0)

⚠️ Atenção! Atributos, pseudo-classes e pseudo-elementos apenas adicionam mais peso em suas respectivas posições, assim como adicionar uma classe ou um elemento ao seletor.

Então, quanto mais relevante for o peso adicionado ao seletor, ou seja, números adicionados as casas mais a esquerda, mais específico o seletor será.

Cascata & Especificidade

Um outro fator que define qual estilo será aplicado, é o comportamento de cascata do CSS. A ordem e o local onde o estilo for declarado pode influenciar na estilização. Veja um exemplo bem simples disso:

p {
    color: blue;
}

p {
    color: white;
}

O comportamento de cascata faz com que a cor do parágrafo seja branca, visto que foi declarado por último. O mesmo vale para seletores mais complexos. Se a especificidade do elemento for o mesmo, a ordem em que foram definidos é que define qual estilo será aplicado.

Como dito anteriormente, o local onde o css é definido também tem um papel muito importante na hora de definir quem terá a precedência. Segue uma lista em ordem decrescente dos locais com maior precedência. Quem possui maior prioridade está no topo.

  1. Inline CSS HTML <p style="color: white">Hello World!</p>
  2. CSS Embutido/CSS Externo HTML <style> p { color: white } </style> HTML <link rel="stylesheet" href="style.css">
  3. Inline Attributes HTML <p color="white">Hello World!</p>
  4. Herança HTML <div color="red"> <p>Hello World!</p> </div>

Em relação ao CSS Embutido/ CSS Externo, é importante mencionar que terá maior prioridade quem for declarado por último, mas respeitando os aspectos de especificidade do seletor. Veja o exemplo:

style.css

p {
    color: red;
}

index.html

<link rel="stylesheet" href="style.css">
<style> p { color: white } </style>

No exemplo acima, criamos um arquivo css chamado style.css e o importamos no nosso index.html. No entanto, o import do arquivo está ocorrendo antes da declaração do CSS embutido, logo, o parágrafo será branco. Porém, se mudarmos a ordem, como feito abaixo…

index.html

<style> p { color: white } </style>
<link rel="stylesheet" href="style.css">

Como agora estamos importando o arquivo style.css por último, o parágrafo será vermelho. Imagine como se estivéssemos concatenando o arquivo style.css no index.html, resultando em algo mais ou menos assim:

p {
    color: green;
}

p {
    color: red;
}

!important demais é veneno

O CSS disponibiliza uma forma de “burlar” os níveis de especificidade através da palavra-chave !important.

p {
    color: red!important;
}

O estilo que for marcado jutamente com essa palavra-chave terá prioridade acima dos outros seletores, mas respeitando o comportamento de cascata mencionado anteriormente. Então, muito cuidado ao usá-lo.

Outras dicas

Particularmente, eu desconheço as boas práticas oficialmente estabelecidas pela documentação ou pela comunidade, então não tenho propriedade para ditar regras. O que eu posso falar com propriedade é sobre minha experiência de desenvolvimento e as dicas/ferramentas que me ajudaram.

  1. Evite usar a palavra-chave !important
  2. Tente aderir a alguma metodologia como a Block Element Modifier (BEM)
  3. Alguns editores de texto auxiliam na hora de calcular a especificidade do seu seletor. O VSCode, por exemplo, no seu arquivo CSS, basta colocar o mouse sob o seu seletor e você verá o cálculo de especificidade

Espero que tenham gostado e que essa publicação tenha esclarecido esses conceitos. Caso você tenha mais dicas para passar, ou gostaria de adicionar algo a discussão, junte-se a nós nos comentários, será um prazer interagir com você!

Até a próxima e bons estudos!