Pular para o conteúdo
Cursos

DevClub

LógicaFront-endBack-endMobile

IA Club

IA na prática
Estudar programaçãoEstudar IA
LiçãoIniciantecódigo testado

Seletores e cascata CSS: estilize sem adivinhar

Aprenda a encontrar elementos com seletores CSS e entenda como a cascata escolhe a regra vencedora, com uma vitrine testada no navegador.

Rodolfo Mori6 min de leitura

Seletores CSS encontram os elementos que você quer estilizar; a cascata decide qual valor fica quando mais de uma regra tenta alterar a mesma propriedade. Com essas duas ideias, você consegue olhar uma página e explicar por que cada cor apareceu, em vez de trocar valores até alguma coisa funcionar.

Nesta lição, a gente vai montar dois cartões da Livraria Beira-Rio. O HTML, o CSS e as medições foram executados no Google Chrome 151.0.7922.170. Se a sintaxe de class e de data-* ainda parece nova, passe antes por tags e atributos HTML e volte para continuar.

O endereço que leva a regra até o elemento

Imagine a separação de encomendas de um prédio. “Entregue no prédio” é amplo; “entregue nos apartamentos do sexto andar” reduz o grupo; “entregue no 604” aponta para um destino específico. Um seletor CSS faz esse trabalho de localização: ele descreve quais elementos da árvore HTML combinam com a regra.

Nesse mapa, o prédio é o documento, os apartamentos são os elementos, e nomes como .produto-card ou [data-categoria="livro"] são critérios do endereço. O bloco entre chaves contém as declarações que serão entregues. A comparação tem um limite importante: o navegador não “entende a intenção” do endereço. Ele compara a sintaxe do seletor com a árvore HTML, seguindo regras formais.

Comece pela vitrine abaixo. Há dois article, ambos com a classe produto-card, mas apenas o primeiro tem o atributo data-categoria="livro".

html
<div class="vitrine">
  <article class="produto-card destaque" data-categoria="livro">
    <h2>O Cortiço</h2>
    <p class="status">Últimas unidades</p>
    <button class="botao-comprar" type="button">Adicionar</button>
  </article>

  <article class="produto-card" data-categoria="papelaria">
    <h2>Caderno</h2>
  </article>
</div>

Agora aplique três formas de localizar essas peças:

css
.produto-card {
  padding: 12px;
}

[data-categoria="livro"] {
  background: rgb(255 247 214);
}

.vitrine > .produto-card {
  border-left: 6px solid rgb(30 100 50);
}

.produto-card é um seletor de classe e encontra os dois cartões. O trecho entre colchetes é um seletor de atributo e encontra apenas o livro. O > é um combinador de filho direto: ele só aceita cartões que estejam logo dentro da vitrine, sem outro elemento entre os dois.

Uma forma objetiva de conferir o endereço é usar querySelectorAll. Ele usa a mesma sintaxe de seletores e devolve quantos elementos combinaram:

js
console.log('cartões:', document.querySelectorAll('.produto-card').length);
console.log(
  'livros:',
  document.querySelectorAll('[data-categoria="livro"]').length,
);
console.log(
  'filhos diretos:',
  document.querySelectorAll('.vitrine > .produto-card').length,
);
cartões: 2 livros: 1 filhos diretos: 2

Essa saída é um hábito de depuração útil: antes de discutir cor, confirme se o seletor chegou aos elementos esperados. Um seletor que encontra zero elementos não perde na cascata; ele nem entra na disputa.

Como ler uma regra CSS sem decorar

Uma regra completa tem seletor e bloco de declarações. Em cada declaração, vem uma propriedade, dois-pontos, um valor e ponto e vírgula. Leia a primeira linha abaixo como uma frase: “para todo elemento com a classe status, defina a propriedade color como este tom de verde”.

css
.status {
  color: rgb(12 96 56);
  font-weight: 700;
}

O seletor responde quem. color e font-weight respondem o quê. Os valores respondem como fica. Separar as três perguntas torna uma regra longa menos assustadora e ajuda a pesquisar a parte certa na documentação.

Os seletores que mais aparecem no começo são estes:

tipo sintaxe o que encontra na vitrine
elemento article todos os artigos
classe .produto-card todo cartão com essa classe
id #ofertas o único elemento com esse id
atributo [data-categoria="livro"] o cartão marcado como livro
pseudo-classe .botao-comprar:hover o botão enquanto o ponteiro está sobre ele

Você pode juntar critérios. .produto-card.destaque exige as duas classes no mesmo elemento. Também pode descrever relações: .produto-card .status encontra um descendente com classe status em qualquer profundidade; o > exige um filho direto. Essa diferença fica importante no erro reproduzido daqui a pouco.

Quando duas instruções chegam ao mesmo cartão

O nome Cascading Style Sheets pode ser traduzido como “folhas de estilo em cascata”. Cascata é o algoritmo usado para ordenar declarações concorrentes. No exemplo a seguir, as duas regras encontram o mesmo parágrafo e tentam definir a mesma propriedade:

css
.status {
  color: rgb(12 96 56);
  --regra-status: "primeira regra";
}

.status {
  color: rgb(148 44 44);
  --regra-status: "segunda regra de mesma força";
}

As duas têm a mesma origem, importância e força do seletor. Nesse empate, a ordem de aparição decide, e a segunda declaração vence. Uma propriedade personalizada guarda o nome da vencedora para a gente conferir no estilo calculado do navegador:

js
const status = document.querySelector('.status');
const estilo = getComputedStyle(status);

console.log('cor:', estilo.color);
console.log('regra:', estilo.getPropertyValue('--regra-status').trim());
cor: rgb(148, 44, 44) regra: "segunda regra de mesma força"

Então a última regra sempre vence? Não. Antes da ordem, a cascata considera a origem da declaração, se existe !important, as camadas, a especificidade e, quando aplicável, a proximidade de escopo. A ordem no arquivo é o desempate final. A lição de especificidade no CSS abre essa conta sem recorrer a “tentativa e erro”. Por enquanto, mantenha seletores curtos e classes reutilizáveis.

Herança é outro mecanismo. Certas propriedades, como color, passam do pai para os descendentes quando eles não receberam um valor próprio; border e margin, em geral, não passam. A herança fornece um valor, e a cascata resolve as declarações que realmente disputam aquela propriedade. Os nomes se relacionam, mas não são sinônimos.

Uma pseudo-classe mostra uma situação passageira

Pseudo-classe é um seletor que representa um estado. :hover combina enquanto o dispositivo aponta para o elemento; :focus-visible ajuda a mostrar onde está o foco do teclado; :checked reconhece um controle marcado. Ela não cria uma classe no HTML.

css
.botao-comprar {
  border: 0;
  padding: 8px 12px;
  background: rgb(37 99 235);
  color: white;
  transform: translateY(0);
}

.botao-comprar:hover {
  background: rgb(30 64 175);
  transform: translateY(-2px);
}

No teste automatizado, o navegador leu os estilos antes e depois de posicionar o ponteiro no botão:

js
const botao = document.querySelector('.botao-comprar');

function estadoDoBotao() {
  const estilo = getComputedStyle(botao);
  return {
    background: estilo.backgroundColor,
    transform: estilo.transform,
  };
}

console.log(estadoDoBotao());
antes: background rgb(37, 99, 235); transform matrix(1, 0, 0, 1, 0, 0) hover: background rgb(30, 64, 175); transform matrix(1, 0, 0, 1, 0, -2)

O -2 no último número da matriz confirma o deslocamento vertical de dois pixels. Em telas de toque, hover não deve carregar uma informação essencial, porque nem todo dispositivo mantém esse estado. Use-o como reforço visual.

O espaço que faz o seletor procurar outra pessoa

Agora reproduza um erro pequeno e muito comum. O cartão do livro tem as classes produto-card e destaque no mesmo article. Alguém escreve este seletor:

css
.produto-card .destaque {
  outline: 3px solid tomato;
}

O espaço diz “procure um elemento .destaque dentro de .produto-card”. Só que não existe esse descendente; as duas classes estão na mesma pessoa. O navegador não exibe uma mensagem de erro, porque o seletor é válido. Ele apenas combina com zero elementos.

js
console.log(
  'com espaço:',
  document.querySelectorAll('.produto-card .destaque').length,
);
console.log(
  'sem espaço:',
  document.querySelectorAll('.produto-card.destaque').length,
);
com espaço: 0 sem espaço: 1

Corrija removendo o combinador:

css
.produto-card.destaque {
  outline: 3px solid tomato;
}

O padrão de investigação é mais importante que decorar o caso: abra o painel Elements, busque o seletor ou rode document.querySelectorAll, confira a quantidade, e só depois analise a cascata. Isso separa “não encontrei o alvo” de “encontrei, mas outra regra venceu”.

Sua missão: criar um estado verificável

Copie um dos cartões e troque o atributo dele para data-categoria="promocao". O novo requisito é pintar apenas essa categoria e dar uma borda ao cartão que também tiver a classe destaque.

html
<article class="produto-card destaque" data-categoria="promocao">
  <h2>Memórias Póstumas de Brás Cubas</h2>
  <p class="status">30% de desconto</p>
</article>
css
[data-categoria="promocao"] {
  background: rgb(254 226 226);
}

.produto-card.destaque {
  border-left: 6px solid rgb(185 28 28);
}

O critério de sucesso tem duas partes: document.querySelectorAll precisa devolver 1 para cada seletor, e o inspetor do navegador deve mostrar as duas declarações ativas no mesmo article. Depois, mova a regra do atributo para o começo do arquivo. O resultado não muda, porque ela não disputa a mesma propriedade da borda.

Na sequência, aprenda por que largura, preenchimento e borda mudam o tamanho real de cada cartão em box model no CSS. Quando o layout chegar a fileiras e alinhamento, continue em Flexbox no CSS. E, se quiser alterar uma classe em resposta a um clique, conecte este fundamento a como alterar CSS com JavaScript.

  • css
  • seletores
  • cascata
  • pseudo-classes
  • heranca

Perguntas frequentes

Qual é a diferença entre seletor e propriedade CSS?
O seletor encontra os elementos que receberão uma regra. A propriedade identifica o que será alterado, como color, padding ou display, e o valor diz qual será o resultado dessa alteração.
A última regra CSS sempre vence?
Não. A ordem de escrita só desempata declarações que já chegaram à mesma origem, camada e importância e têm a mesma especificidade. Uma regra mais forte pode vencer mesmo aparecendo antes no arquivo.
Posso usar o mesmo nome de classe em vários elementos?
Sim. Classe existe justamente para identificar um grupo reutilizável. Um id deve ser único na página; uma classe como produto-card pode aparecer em todos os cartões da vitrine.
Por que um espaço muda tanto um seletor CSS?
Porque o espaço é um combinador de descendente. .card.destaque procura um elemento que tenha as duas classes; .card .destaque procura outro elemento, com a classe destaque, dentro de .card.

Dúvidas e comentários

Travou em algum passo? Pergunte aqui — a equipe e outros alunos respondem.

Todo o código deste artigo foi executado em Google Chrome 151.0.7922.170, e as saídas exibidas são as reais — como produzimos este conteúdo.

Fontes consultadas

  1. MDN — CSS selectors — developer.mozilla.org
  2. MDN — Cascade, specificity, and inheritance — developer.mozilla.org
  3. Selectors Level 4 — W3C — w3.org
  4. CSS Cascading and Inheritance Level 5 — W3C — w3.org

Continue por aqui