Calculadora de Especificidade CSS
Calcule a especificidade CSS de qualquer seletor. Decomposição colorida, comparação múltipla, suporta :is, :not, :has, :where conforme W3C.
| Componente | Exemplos | Peso |
|---|---|---|
| a IDs | #header, #main | (1, 0, 0) |
| b Classes / Atributos / Pseudo-classes | .btn, [type="text"], :hover, :nth-child(2) | (0, 1, 0) |
| c Tipos / Pseudo-elementos | div, p, ::before, ::placeholder | (0, 0, 1) |
| — | *, :where(...), +, >, ~ | (0, 0, 0) |
| — | :is(A, B), :not(A), :has(A) | max do argumento |
Calculadora de Especificidade CSS — Analise Seletores, Calcule (a, b, c)
Cole qualquer seletor CSS — simples ou composto, com combinadores, pseudo-classes, pseudo-elementos, ou os modernos :is/:not/:where/:has — e a calculadora retorna a tripla de especificidade W3C. A decomposição mostra a qual componente cada token contribui, e uma vista de comparação classifica vários seletores para você ver de relance qual regra vence a cascata.
O que é especificidade CSS em um parágrafo?
Quando duas regras CSS tentam definir a mesma propriedade no mesmo elemento, o navegador precisa de um critério de desempate. O primeiro é *origem e importância* (user-agent < autor < usuário, depois !important inverte). Em seguida, *especificidade*: cada seletor recebe um peso, expresso em três números — (a, b, c) — e a tupla maior vence, comparando da esquerda para a direita.
Os três slots contam:
- **a** — número de seletores ID (`#foo`)
- **b** — número de seletores de classe (`.bar`), atributo (`[type=text]`), e pseudo-classes (`:hover`)
- **c** — número de seletores de tipo (`div`) e pseudo-elementos (`::before`)
Um seletor como `#nav .item a:hover` tem um ID, duas entradas classe/pseudo-classe, e um tipo — especificidade (1, 2, 1). Vence `.menu .item a:focus` (0, 3, 1) porque o primeiro slot ganha independente de quão altos sejam os slots posteriores.
Como `:is()`, `:not()`, e `:has()` afetam a especificidade?
Os três contribuem com a especificidade *máxima* dos seus argumentos, não zero, não a soma.
Exemplo:
```
:is(.btn, #primary) { color: red; }
```
A especificidade é determinada por `#primary` (1, 0, 0), não por `.btn` (0, 1, 0). O token completo `:is(...)` contribui (1, 0, 0).
A mesma regra aplica a `:not(...)` e `:has(...)` — eles pegam o seletor mais pesado dentro dos parênteses. Por isso `:not(#admin)` é um seletor pesado apesar de parecer inocente; é especificidade (1, 0, 0) sozinho.
Este comportamento está definido em CSS Selectors Level 4. O `:not()` antigo (Level 3, forma simples de um seletor único) seguia a mesma regra, então a maioria dos navegadores sempre concordou.
E `:where(...)`?
`:where(...)` é a válvula de escape: contribui **especificidade zero** independente do que contenha.
```
:where(#header, .nav, h1) { color: blue; }
```
Especificidade = (0, 0, 0). Isto é intencional. `:where()` permite escrever um estilo base que seletores agrupados compartilham sem bloquear futuras sobrescritas — qualquer coisa que mire os mesmos elementos com nem que seja uma classe vai vencer.
Um padrão comum é envolver regras de reset ou padrão em `:where(...)` para que elas tenham efetivamente nenhum peso de especificidade, enquanto estilos de componente autorais ficam livres para sobrescrevê-las com seletores normais. Adicionado em CSS Selectors Level 4 (2018) e entregue em todos os navegadores evergreen até 2021.
Por que às vezes vejo `(a, b, c, d)` com quatro slots?
Artigos antigos adicionam um quarto slot no início para **estilo inline** (o atributo `style="..."`), dando (1, 0, 0, 0) para qualquer declaração inline. O W3C tirou isso da tupla formal de especificidade porque o estilo inline é uma camada de origem separada — ele vence todas as decisões de cascata no nível autor antes mesmo da especificidade ser comparada.
Na prática:
1. Declarações `!important` vencem (camada de origem).
2. Estilo inline vence qualquer seletor sem `!important`.
3. Seletores são então classificados por (a, b, c) — IDs, classes/attrs/pseudo-classes, tipos/pseudo-elementos.
4. Se a especificidade empata, a regra declarada por último em ordem de fonte vence.
Esta calculadora segue a convenção moderna de três slots. Se comparando com um tutorial mais antigo, preencha mentalmente com um 0 inicial — `(0, 1, 2, 1)` e `(1, 2, 1)` descrevem o mesmo seletor.
Duas das minhas regras empatam em especificidade — qual vence de fato?
Este é o bug CSS mais comum do mundo real: dois seletores atingem o mesmo elemento com a tupla de especificidade *idêntica*, p. ex. tanto `.card .title` quanto `.panel .heading` em (0, 2, 0). A especificidade sozinha não desempata, então o navegador recorre ao próximo passo da cascata.
A ordem de resolução, quando a especificidade é igual, é:
1. **Camadas de cascata** (`@layer`) — uma declaração em uma camada declarada depois vence uma camada anterior, e estilos sem camada vencem os com camada. Isso anula a especificidade por completo dentro da origem de autor.
2. **Ordem de origem** — se ambas as regras estão na mesma camada (ou nenhuma camada é usada), vence a regra declarada por *último*. O posterior vence.
É por isso que a tabela de comparação desta calculadora agora inclui uma coluna **Vencedor na Cascata**: cole seus seletores empatados na ordem em que aparecem na sua folha de estilos, e a ferramenta marca o grupo de especificidade igual e sinaliza o vencedor pela ordem de origem (a última linha). Assim, se `.card .title` está na linha 12 e `.panel .heading` na linha 30, a linha 30 vence — a ferramenta diz isso explicitamente em vez de deixar você lembrar a regra.
Note que a ferramenta modela apenas o desempate por *ordem de origem*; ela não analisa `@layer` nem `!important`, que estão acima da ordem de origem na cascata. Se suas regras estão em camadas diferentes, a ordem das camadas decide independentemente de qual linha vem depois.

Como vencer uma declaração de estilo inline `style="..."`?
Um atributo de estilo inline supera *qualquer* regra baseada em seletor que não use `!important`, não importa quão alta seja sua especificidade. `style="color:red"` vence até `#a#b#c.d.e div { color: blue; }` porque o estilo inline ocupa um slot mais alto da cascata do que a especificidade comum de seletores.
Suas opções, em ordem de preferência:
1. **Remova o estilo inline** — a solução limpa. Estilos inline costumam ser injetados por um script ou template legado; mova o valor para uma regra de folha de estilos.
2. **Use `!important`** em uma regra de folha de estilos — uma declaração `!important` de autor vence um estilo inline que *não* seja ele mesmo `!important`. Este é o único uso legítimo de `!important` ao qual muitos engenheiros recorrem aqui.
3. **Um `!important` inline** (`style="color:red !important"`) vence um `!important` de folha de estilos — e aí você volta a editar a marcação.
A especificidade nunca entra nessa briga: você não consegue superar um estilo inline só com seletores. Esta calculadora pontua seletores, então estilos inline ficam fora do escopo por design — mas saber que eles vencem este nível é essencial ao depurar por que uma regra não se aplica.
O seletor universal `*` ou combinadores adicionam especificidade?
Não. Nada do seguinte contribui para a especificidade:
- `*` (seletor universal)
- ` ` (combinador de descendente, escrito como espaço)
- `>` (combinador de filho)
- `+` (combinador de irmão adjacente)
- `~` (combinador de irmão geral)
- `||` (combinador de coluna, para tabelas — Level 4)
Um seletor como `* > * + *` tem especificidade (0, 0, 0) — três universais e dois combinadores, todos sem peso. Combinadores descrevem *relações*, não o que está sendo selecionado, então não adicionam peso.
É por isso que `body > main p` (0, 0, 3) empata com `h1 ~ h2 ~ p` (0, 0, 3) — mesmos três seletores de tipo, combinadores diferentes, mesma especificidade. A cascata decide então por ordem de fonte.
Qual a diferença entre pseudo-classes e pseudo-elementos?
**Pseudo-classes** descrevem um estado de um elemento:
- `:hover`, `:focus`, `:active`, `:checked`, `:disabled`
- `:nth-child(2)`, `:nth-of-type(odd)`, `:first-child`
- `:lang(en)`, `:dir(rtl)`, `:state(custom)`
Contribuem para o slot **b** — mesmo peso que um seletor de classe.
**Pseudo-elementos** descrevem uma sub-parte virtual de um elemento:
- `::before`, `::after`, `::first-line`, `::first-letter`
- `::placeholder`, `::marker`, `::backdrop`, `::selection`
Contribuem para o slot **c** — mesmo peso que um seletor de tipo.
A diferença sintática é dois-pontos único (`:hover`) vs dois-pontos duplo (`::before`). CSS2 usava dois-pontos único para os quatro pseudo-elementos mais antigos (`:before`, `:after`, `:first-line`, `:first-letter`) — esta calculadora aceita ambas formas e classifica esses quatro como pseudo-elementos em qualquer caso.
Como reduzo a especificidade quando estou em guerra com outra folha de estilos?
Várias técnicas em severidade crescente:
1. **Use `:where()`** — envolva as partes pesadas do seu seletor em `:where()` para que não contribuam nada. `:where(.legacy) .button` → (0, 1, 0) em vez de (0, 2, 0). Melhor para folhas reset.
2. **Tire IDs dos seletores** — refatore `#nav .item` para `.nav .item` se o markup permitir. IDs são o contribuinte mais pesado sozinho.
3. **Use uma única classe** — seletores planos como `.btn-primary` vencem porque empatam em (0, 1, 0) contra a maioria dos estilos autorais, deixando a ordem de fonte decidir.
4. **Duplique uma classe** — `.btn.btn` (0, 2, 0) é um hack conhecido para aumentar a especificidade *sem* precisar de IDs.
5. **Use cascade layers** — `@layer base, components, utilities;` permite controlar qual arquivo vence independente da especificidade. A camada declarada depois vence, ponto.
6. **Use `!important`** — último recurso. Funciona mas cria uma cadeia frágil de guerras de sobrescrita.
A estratégia moderna é: minimizar especificidade em CSS de componente (classes únicas), envolver regras legacy/reset em `:where()`, e usar cascade layers para a divisão tooling/utility.
Esta calculadora é privada e offline?
Sim. Tudo é calculado localmente no navegador por algumas centenas de linhas de JavaScript:
- O parser de seletores é escrito à mão, sem nenhum engine CSS externo chamado.
- Sem telemetria, sem analytics para os cálculos em si.
- O botão Exemplos preenche o textarea com strings embutidas; nada é baixado.
- A página compartilha os assets normais do site (Bootstrap CSS, ícones) mas nenhuma API de terceiros é contatada para a matemática real de especificidade.
Você pode verificar abrindo DevTools → Rede e observando enquanto digita ou clica em Calcular — nenhuma requisição deveria disparar. Isso também significa que a calculadora funciona offline depois que a página carrega, útil se estiver auditando uma folha de estilos em voo ou em zona com sinal fraco.
Recursos Principais
- Tupla (a, b, c) correta segundo W3C para qualquer seletor CSS
- Decomposição colorida destacando qual token contribui para cada slot
- Vista de comparação multi-seletor, ordenada por especificidade decrescente
- Manuseio correto de :is(), :not(), :has() — especificidade max do argumento
- :where(...) reconhecido como especificidade zero
- Pseudo-elementos (::before, ::after, ::first-line) classificados separadamente de pseudo-classes
- Pseudo-elementos CSS2 com dois-pontos único (:before, :after) aceitos
- Seletor universal * e combinadores (>, +, ~, espaço) corretamente com peso zero
- Seletores de atributo, incluindo [attr=value] e [attr^=value]
- Pseudo-classes funcionais :nth-child(), :nth-of-type(), :lang(), :dir()
- Preset Exemplos carrega 10 seletores representativos para comparação instantânea
- Detecção de empate — destaca seletores com mesma especificidade
- JavaScript puro, sem engine CSS externo
- Funciona offline após o primeiro carregamento
- 100% no cliente — seus seletores ficam no seu navegador
