Curso de CSS / Herança, especificidade e cascata
A cascata escolhe entre declarações CSS concorrentes, enquanto a especificidade compara a força dos seletores dentro das condições relevantes da cascata. A herança fornece certos valores de um elemento pai quando nenhuma declaração aplicável os determina; estes são mecanismos relacionados, mas diferentes.
Distinga herança de declarações diretas
Herança é quando um elemento filho herda o valor de seu elemento pai. Enquanto a cor do texto e propriedades relacionadas à fonte são geralmente herdadas, borda e padding não são herdados por padrão. Se você assumir que todas as propriedades serão iguais às do pai, pode acabar encontrando bordas inesperadas em seus parágrafos.
#main {
color: purple;
border: 1px solid purple;
}
p { color: #555; }
<main id="main">
<h1>Small Garden</h1>
<p>Visitor information.</p>
</main>
Assumindo que aplicamos apenas essas duas peças, h1 herdará a cor roxa de seu pai main. A cor cinza que você especifica é aplicada ao p. Só porque o #main do pai é um seletor de ID, isso não prevalece sobre a atribuição direta do p filho. Isso ocorre porque não há uma competição entre dois seletores aplicando-se ao mesmo elemento. A borda é criada ao redor da caixa de main e não é duplicada pelas bordas de h1 e p, respectivamente.
Propriedades não herdadas também podem herdar o valor calculado do pai especificando-o como border: inherit. Por outro lado, mesmo que haja uma declaração que se aplique ao elemento, mesmo que seja uma propriedade herdada, essa declaração é processada primeiro. Você pode descobrir quais propriedades são herdadas e o que herdar significa na descrição de herança de CSS da MDN.
Siga o processo de decisão da cascata
Comece com o CSS do autor comum, como as regras que você escreve para esta página. Antes de comparar declarações, verifique se o seletor corresponde, se a sintaxe é válida e se condições como consultas de mídia se aplicam. Exclua regras não correspondentes e declarações inválidas da comparação.
- Verifique as principais condições, como origem, importância e camada. Origem CSS do autor e CSS do usuário/padrão do navegador, se é !important, se @layer é usado, etc. são relevantes aqui. Se as principais condições forem diferentes, a decisão não é tomada apenas comparando os valores dos seletores.
- Compare a especificidade do seletor dentro das mesmas condições. Prioridade (especificidade) é um critério para comparar quão específico um seletor é. Compare ID, família de classes e família de elementos nessa ordem.
- Se a prioridade for a mesma, a declaração escrita por último é utilizada. Em situações onde não há condições adicionais, como @scope, como nos exemplos desta lição, os empates finais são resolvidos pela ordem de origem.
- Para cada propriedade, o CSS resolve as declarações aplicáveis e então realiza o preenchimento padrão quando necessário. Propriedades herdáveis podem obter um valor do elemento pai; outras propriedades normalmente usam seu valor inicial. Isso não significa que toda declaração em uma regra vencedora substitua uma regra anterior inteira.
A cascata é o processo completo de resolução de conflitos do CSS; a especificidade do seletor é um critério dentro dele. Animações, transições, camadas e escopos introduzem regras adicionais, portanto, os exemplos simples aqui não representam todos os casos. As regras de ordenação da cascata do W3C definem os relacionamentos entre origem, importância e camadas. O exemplo completo abaixo não utiliza animações, transições, @layer ou @scope. O artigo Organize o CSS com Estilos Compartilhados, Aninhamento e Camadas demonstra como agrupar regras em camadas.
Compare a especificidade em três colunas
O seletor básico nesta lição pode ser lido em três colunas: número de IDs, número de classes/atributos/pseudo-classes e número de elementos/pseudo-elementos. Compare da coluna da esquerda e, se houver diferença, decida com base no resultado. Não memorize apenas como uma tabela de pontuação decimal somando ID=100, classe=10, elemento=1. Só porque há muitas classes não significa que ultrapassa a coluna de ID.
| seletor | ID | Classe, atributo, pseudo-classe | Elemento/Pseudo-elemento | notação |
|---|---|---|---|---|
p |
0 | 0 | 1 | 0-0-1 |
.notice |
0 | 1 | 0 | 0-1-0 |
p.notice |
0 | 1 | 1 | 0-1-1 |
[required] |
0 | 1 | 0 | 0-1-0 |
a:hover |
0 | 1 | 1 | 0-1-1 |
p::before |
0 | 0 | 2 | 0-0-2 |
#opening |
1 | 0 | 0 | 1-0-0 |
#main .notice |
1 | 1 | 0 | 1-1-0 |
p.notice e .notice têm a mesma coluna de ID e a mesma coluna de classe. Há uma diferença entre 1 e 0 na coluna de elemento, então p.notice tem maior especificidade. #opening e p.notice têm uma diferença de 1 e 0 na primeira coluna, então #opening tem maior especificidade. Espaços em branco, notações relacionais como >, +, ~ e o seletor universal * não aumentam diretamente o número dessas comparações.
p.notice { color: #087f5b; }
.notice { color: tomato; }
Sob as mesmas condições de origem, importância e camada, p.notice tem maior especificidade que .notice, então sua cor verde vence mesmo quando aparece antes. Seletores idênticos têm especificidade igual, permitindo que a ordem de origem resolva um empate. Algumas pseudo-classes funcionais têm regras adicionais de especificidade. Veja MDN: Especificidade.
Resolva cada propriedade separadamente
.notice {
color: blue;
padding: 12px;
border: 1px solid #087f5b;
}
.notice {
color: tomato;
padding: 20px;
}
Se apenas essas duas regras forem aplicadas ao mesmo elemento, cor e padding usam a declaração da última, e a borda da regra anterior permanece. Só porque não há borda na regra seguinte não significa que toda a regra anterior desaparece. O CSS deve ser entendido como “determinando valores para cada propriedade” em vez de “selecionando um bloco de regra inteiro”.
Por exemplo, a cor do texto pode vir de uma regra de ID, a margem pode vir de uma regra de classe posterior, e a borda pode vir de uma regra de classe anterior. Mesmo quando você vê o texto riscado nas ferramentas de desenvolvimento, leia as declarações uma a uma. Só porque a cor está riscada não significa que o padding do mesmo bloco não está aplicado.
Preveja o resultado do exemplo completo antes de executá-lo
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Small Garden</title>
<style>
body { margin: 24px; font-family: sans-serif; line-height: 1.7; }
#main { color: purple; }
p { color: #555; }
.notice {
color: blue;
padding: 12px;
border: 1px solid #087f5b;
}
p.notice { color: #087f5b; }
.notice { color: tomato; padding: 20px; }
#opening { color: #1d4ed8; }
</style>
</head>
<body>
<main id="main">
<h1>Small Garden</h1>
<p id="opening" class="notice">A: We open at 9am every day.</p>
<p class="notice">B: Prepare a water bottle and comfortable shoes.</p>
<p>C: Please inquire at the information desk.</p>
</main>
</body>
</html>
Preveja as cores de A·B·C e o espaçamento interno do aviso antes de abri-lo em seu navegador. Se você salvar todo o código como index.html e abrir, você obterá o seguinte resultado. A fonte do body e a altura da linha são configurações auxiliares para facilitar a visualização.
| objeto e propriedades | resultado final | Motivo da decisão |
|---|---|---|
| cor do h1 | Roxo | Herdou a cor do main. Não há outras declarações de cor no h1. |
| cor de A | Azul #1d4ed8 | #opening tem especificidade maior que p.notice, .notice, p aplicados ao mesmo A. |
| cor de B | Verde #087f5b | p.notice tem maior especificidade que a regra .notice escrita depois. |
| cor de C | Cinza #555 | Usa um valor direto para p e não herda a cor roxa do pai. |
| preenchimento de A·B | 20px | As duas declarações .notice têm a mesma especificidade, então o preenchimento da última prevalece. |
| borda de A·B | linha sólida verde de 1px | Como não há declaração de borda na última regra, a declaração válida anterior permanece. |
Quando verificado em Computed, a cor de A pode ser exibida como rgb(29, 78, 216), a cor de B pode ser exibida como rgb(8, 127, 91), e a cor de C pode ser exibida como rgb(85, 85, 85). Mesmo que a notação da cor seja diferente, indica o mesmo valor. Verifique se o preenchimento é 20px em cada direção e se a espessura e o formato da linha da borda são os mesmos.
Compare !important e estilos inline
!important é uma notação que altera a importância de uma declaração. Não é uma função que adiciona um grande número às três colunas do seletor. Na origem de autor, nas condições deste exemplo, declarações importantes têm precedência sobre declarações comuns, então adicionar a regra abaixo ao final de todo o exemplo mudará a cor de A e B para tomato (vermelho alaranjado). A declaração de cor simples no ID também não tem precedência sobre esta declaração importante.
.notice { color: tomato !important; }
Este resultado não significa que important é sempre mais forte do que todos os estilos. Estilos importantes do usuário, valores durante transições, etc., seguem uma ordem separada. Mesmo entre declarações importantes, você deve primeiro verificar a origem e a camada. Neste exercício, observe o important e depois exclua a regra que você adicionou. Normalmente, é melhor para manutenção organizar primeiro o intervalo de seleção e a estrutura.
<p class="notice" style="color: purple;">B: Information on what to prepare</p>
No exemplo original onde a regra important foi deletada, se você colocar uma cor inline em B como acima, ela terá precedência sobre as regras regulares da folha de estilo e B se tornará roxo. Estilos inline são tratados separadamente das três colunas de seletores padrão na tabela acima. Novamente, colocar important na regra da classe geral permite que ela tenha precedência sobre a cor inline regular. Portanto, “se for inline, é incondicionalmente o mais forte” também é uma explicação sem condições.
Pratique diagnosticar conflitos
- No exemplo completo original, mova a regra
p.noticepara o final. Certifique-se de que B ainda esteja verde e que A mantenha a cor azul do seu ID. Em casos com alta especificidade, elas não serão anuladas simplesmente alterando sua ordem. - Em seguida, altere apenas o seletor p.notice para
.noticee coloque-o na parte inferior. A cor de B usa o verde especificado pelo último .notice. Como temos o mesmo seletor, a ordem agora é o critério de decisão. Após a confirmação, restaure o original. - Remova apenas
id="opening"de A. Veja se A se torna do mesmo verde que B. Mesmo que o ID do elemento principal permaneça o mesmo, ele não supera a cor verde atribuída diretamente a A. Após conferir o resultado, restaure o ID de A. - Em etapas separadas, aplique os exemplos de !important e estilos inline e compare os resultados. Volte ao original entre os testes para não deixar regras anteriores interferirem na condição seguinte.
Se o resultado difere da sua expectativa, Inspecione o CSS com DevTools: Styles e Computed. Selecione o elemento correto, encontre as declarações da propriedade, compare sua importância, seletores e ordem, e então inspecione o valor final. Adicionar IDs ou !important sem encontrar a causa pode alterar a cor agora enquanto torna edições futuras mais difíceis.




