Skip to content
This page has been auto-translated and may contain errors.View in English

Seletores CSS

docs.scrimba.com

Você tem uma página cheia de elementos e um conjunto de estilos que deseja aplicar, mas uma cor ou uma fonte não serve para nada até você poder dizer quais elementos ela pertence. Um seletor é como você aponta para os certos: este parágrafo, cada botão, apenas os links dentro da navegação. Fique confortável com seletores e o resto do CSS se torna uma questão de escolher o que mudar, porque você já sabe como alcançá-lo.

Seletores de tipo, classe e id

Uma regra CSS tem duas partes: um seletor que escolhe quais elementos estilizar, e um bloco de declarações que diz como. O seletor mais simples é o nome do elemento, chamado de seletor de tipo. Escreva p e cada parágrafo da página é estilizado.

Isso geralmente é muito amplo. Você raramente quer que todos os parágrafos pareçam iguais. Então você dá aos elementos um rótulo chamado classe, usando o atributo HTML class, e aponta esse rótulo do CSS com um ponto na frente. Pense em uma classe como um crachá: você cola a mesma tag em cada elemento que deseja tratar como um grupo, depois estiliza a tag uma vez.

Existem três maneiras básicas de apontar para um elemento. Um seletor de tipo corresponde pelo nome da tag (p corresponde a cada parágrafo). Um seletor de classe corresponde pelo atributo class e é escrito com um ponto na frente (.button). Um seletor de id corresponde pelo atributo id e é escrito com um hash na frente (#header).

Use classes como seu gancho de estilização padrão. Uma classe pode ir em quantos elementos você quiser e um elemento pode ter várias classes, então classes descrevem grupos reutilizáveis: tudo com .card compartilha uma aparência. Seletores de tipo são úteis para estilização base ampla (definir a fonte do corpo, por exemplo), mas são bruscos, porque atingem cada elemento desse tipo. Ids devem ser únicos em uma página, então estilizar através deles prende uma regra a um único elemento e, como você verá em especificidade, eles carregam peso extra que os torna desconfortáveis de sobrescrever.

Três tipos de seletor cobrem o básico, e a distinção entre eles é em parte sobre correspondência e em parte sobre peso. Um seletor de tipo (também chamado de seletor de tag ou elemento) corresponde pelo nome do elemento: p, section, input. Um seletor de classe, escrito .card, corresponde a qualquer elemento cujo atributo class contenha esse token, e o atributo é separado por espaço, então um elemento pode ter muitas classes. Um seletor de id, escrito #header, corresponde ao único elemento cujo atributo id é igual a esse valor; um id é obrigado a ser único dentro de um documento.

A regra prática é estilizar quase exclusivamente através de classes. Classes são a única das três que é tanto reutilizável quanto baixa em especificidade (o escore de prioridade que o navegador usa para resolver conflitos, coberto no final deste capítulo), o que mantém seus estilos planos e substituíveis. Seletores de tipo pertencem a um pequeno conjunto de regras base: uma reinicialização, a fonte padrão em body, padrões sensatos em a ou input. Ids são legítimos como ganchos JavaScript e como destinos de links de fragmento (#pricing em uma URL), mas como um gancho de estilização são uma armadilha: são únicos então não podem descrever um grupo, e sua alta especificidade significa que uma regra de classe posterior não pode sobrescrevê-los sem escalação. Estilize com classes, reserve ids para âncoras e scripts.

html
<button class="btn-primary">Inscrever-se</button>
<button class="btn-primary">Comprar agora</button>
css
/* seletor de tipo: cada botão na página */
button {
  font-family: inherit;
}

/* seletor de classe: apenas elementos marcados btn-primary */
.btn-primary {
  background: rebeccapurple;
  color: white;
}

Ambos os botões pegam o estilo .btn-primary de uma regra, porque compartilham a classe. Essa reutilização é toda a razão pela qual classes são a ferramenta que você alcança. Isso constrói diretamente sobre como o CSS funciona, onde cada regra emparelha um seletor com um conjunto de declarações.

JunoSeletores de tipo, classe e id Um seletor de tipo como p atinge cada elemento desse tipo, o que geralmente é mais do que você quer. Uma classe é um crachá que você cola nos elementos que se importa e estiliza com um ponto, como .btn-primary. Comece com classes para quase tudo e você não irá tão longe errado.
JunoSeletores de tipo, classe e id Classes são seu gancho padrão: reutilizáveis, e um elemento pode usar várias. Mantenha seletores de tipo para estilos base amplos como a fonte do corpo, e trate ids como muito específicos e muito de uso único para estilização. Poupe-se da dor de cabeça futura e alcance uma classe primeiro.
JunoSeletores de tipo, classe e id Classes são o único seletor básico que é tanto reutilizável quanto de baixa especificidade, o que é exatamente por que você estiliza através delas e mantém suas regras planas. Seletores de tipo ganham seu lugar em uma pequena camada base, e ids pertencem a scripts e âncoras de link, não a estilização. No dia em que uma regra de id se recusa a ser sobrescrita por uma classe posterior, você ficará feliz em tê-los mantido longe.

Combinadores: selecionando por relacionamento

Às vezes você quer estilizar um elemento apenas quando ele fica dentro de outro. Os links em sua navegação devem parecer diferentes dos links em um parágrafo, mesmo que ambos sejam elementos <a>. Você descreve esse relacionamento com um combinador: coloque dois seletores lado a lado com um espaço, e o CSS lê como "o segundo, mas apenas dentro do primeiro".

Então .nav a significa "qualquer link dentro de um elemento com a classe nav". O espaço está fazendo um trabalho real aqui. Não é decoração, é a instrução para olhar dentro.

Um combinador une dois seletores e corresponde com base em como os elementos se relacionam no HTML. O mais comum é o combinador descendente, escrito como um espaço: .nav a corresponde a cada <a> em qualquer lugar dentro de .nav, não importa o quão profundamente aninhado.

Quando você quer apenas filhos diretos e não descendentes mais profundos, use o combinador filho >. .menu > li corresponde a itens de lista que são filhos diretos de .menu, pulando quaisquer listas aninhadas. Também existem dois combinadores de irmãos para elementos que compartilham um pai: o irmão adjacente + corresponde ao elemento imediatamente após outro (h2 + p estiliza o parágrafo logo após um título), e o irmão geral ~ corresponde a qualquer irmão seguinte. Descendente e filho cobrem a maioria do trabalho real; os combinadores de irmãos são úteis para espaçamento e para padrões de formulário.

Um combinador é o caractere entre dois seletores que define o relacionamento estrutural que eles devem satisfazer. O combinador descendente (um espaço) corresponde ao seletor do lado direito quando está aninhado em qualquer lugar dentro do esquerdo, em qualquer profundidade. O combinador filho (>) restringe isso apenas a filhos diretos: .menu > li ignora itens de lista enterrados em um .submenu aninhado. O combinador irmão adjacente (+) corresponde a um elemento que segue imediatamente outro com o mesmo pai, e o combinador irmão geral (~) corresponde a qualquer irmão posterior com o mesmo pai.

Duas coisas valem a pena reter em produção. Primeiro, um seletor composto é lido da direita para a esquerda no matcher do navegador: para .nav a o engine encontra os elementos <a> primeiro, depois sobe para verificar cada um tem um ancestral .nav. É por isso que cadeias descendentes muito longas custam mais e por que um .nav > a apertado pode ser mais barato que um .nav a solto. Segundo, seletores descendentes acoplam seu CSS à sua estrutura de markup: .card .title quebra no momento em que alguém envolve o título em outro elemento. Favorecer uma classe direta no elemento (.card-title) mantém estilos resilientes a mudanças de markup, e você cai para combinadores quando um relacionamento é a coisa que você realmente quer expressar.

css
/* descendente: qualquer link dentro da nav */
.nav a {
  text-decoration: none;
}

/* filho: apenas itens de lista que são filhos diretos de .menu */
.menu > li {
  display: inline-block;
}

A primeira regra alcança cada link aninhado dentro da navegação; a segunda alcança apenas os itens de nível superior do menu e deixa qualquer lista aninhada sozinha. Escolher entre elas é escolher o quão longe você quer que a regra viaje.

JunoCombinadores Um espaço entre dois seletores significa "dentro": .nav a estiliza links que ficam dentro da navegação. Esse espaço é uma instrução, não espaçamento para aparência, então não o deixe cair por acidente. Esse padrão cobre muito da estilização diária.
JunoCombinadores O espaço é o combinador descendente e corresponde em qualquer profundidade; > o reduz apenas a filhos diretos. Irmãos + e ~ estão lá quando você precisa estilizar um elemento com base no que vem antes dele. Descendente e filho lidarão com a maioria do que você escreve dia a dia.
JunoCombinadores Combinadores são úteis, e eles também prendem seu CSS à sua estrutura HTML, então uma longa cadeia descendente como .card .title está a uma refatoração de quebrar. Prefira uma classe direta no elemento e caia para combinadores quando o relacionamento é a coisa real que você quer expressar. A correspondência também é executada da direita para a esquerda, então um > apertado geralmente bate uma cadeia descendente solta.

Pseudo-classes: estilizando por estado

Elementos podem estar em estados diferentes. Um link pode estar parado ou ter o mouse pairando sobre ele. Uma pseudo-classe permite que você estilize um elemento com base em seu estado, e você a escreve com dois-pontos após o seletor.

A que você usará primeiro é :hover. Escreva .btn-primary:hover e esses estilos se aplicam apenas enquanto o ponteiro está sobre o botão, que é como botões e links fornecem essa pequena resposta visual quando você aponta para eles.

Uma pseudo-classe aponta para um elemento em um estado ou posição particular, escrita com dois-pontos: :hover enquanto o ponteiro está sobre ele, :focus quando ele é selecionado para entrada de teclado, :first-child quando é o primeiro elemento dentro de seu pai.

:focus merece atenção porque é uma questão de acessibilidade, não uma gentileza. Pessoas que navegam com um teclado passam de um controle para o próximo, e o estilo :focus é o único sinal dizendo a eles onde estão. Nunca remova contornos de foco sem substituí-los com uma alternativa visível. Também existem pseudo-classes estruturais como :nth-child(), que leva um padrão entre parênteses: :nth-child(odd) corresponde a cada outro elemento, útil para listras em linhas de tabela. :first-child e :last-child pegam as pontas de um grupo sem precisar de uma classe extra.

Uma pseudo-classe (uma palavra-chave após dois-pontos) corresponde a um elemento que está em um dado estado ou posição estrutural, sem você adicionar qualquer markup para isso. Pseudo-classes de estado incluem :hover, :active, e :focus; estruturais incluem :first-child, :last-child, e o parametrizado :nth-child(), cujo argumento é um padrão an+b (:nth-child(2n) é cada segundo elemento, :nth-child(3n+1) é o primeiro de cada grupo de três).

Duas notas de produção. :focus é inegociável para acessibilidade de teclado: usuários de teclado dependem do anel de foco para saber sua posição, então remover o contorno sem uma substituição visível torna uma interface inutilizável para eles. Prefira :focus-visible, que mostra o anel para interação de teclado mas o suprime no clique do mouse, então você obtém tanto uma experiência de ponteiro limpa quanto uma de teclado acessível. No lado estrutural, lembre-se de que :nth-child(n) conta todos os irmãos independentemente do tipo, enquanto :nth-of-type(n) conta apenas irmãos do mesmo elemento, que é a diferença entre uma regra que funciona e uma que contagem silenciosamente mal quando um elemento errante fica na lista.

css
.btn-primary:hover {
  background: purple;
}

/* usuários de teclado precisam de um indicador de foco visível */
.btn-primary:focus-visible {
  outline: 2px solid rebeccapurple;
  outline-offset: 2px;
}

A primeira regra é acionada enquanto o ponteiro está sobre o botão; a segunda desenha um anel claro quando o botão é selecionado por teclado, que é o que mantém a página usável sem um mouse. As escolhas de cor e contorno aqui se conectam a como o CSS funciona e aos valores que você define em qualquer propriedade.

JunoPseudo-classes Uma pseudo-classe estiliza um elemento em um certo estado, escrita com dois-pontos, como :hover para quando o ponteiro está sobre ele. É daí que vem o efeito de hover de um botão. Você o anexa direto ao seletor, sem espaço entre.
JunoPseudo-classes Pseudo-classes correspondem a estado e posição: :hover, :focus, :nth-child(), :first-child. Trate :focus como um requisito de acessibilidade, porque usuários de teclado precisam ver onde estão, então nunca remova o contorno sem uma substituição visível. Esse hábito manterá suas páginas usáveis para todos.
JunoPseudo-classes Alcance :focus-visible sobre :focus simples para que o anel mostre para usuários de teclado mas não no clique do mouse, e nunca lance uma interface que remova o indicador de foco completamente. Observe a armadilha :nth-child versus :nth-of-type: um conta cada irmão, o outro apenas irmãos do mesmo tipo, e a escolha errada conta mal no momento em que um elemento errante cai na lista. É o tipo de bug que parece fino até não parecer.

Pseudo-elementos: estilizando uma parte de um elemento

Uma pseudo-classe estiliza um elemento inteiro em um certo estado. Um pseudo-elemento é diferente: ele permite que você estilize uma parte de um elemento, ou adicione um pequeno pedaço de conteúdo que não está no seu HTML.

Os dois que você encontrará primeiro são ::before e ::after. Eles inserem conteúdo no início ou no final de um elemento, e você diz a eles o que inserir com a propriedade content. Note os dois dois-pontos: esse dois-pontos duplo é como o CSS marca um pseudo-elemento apartado de uma pseudo-classe.

Um pseudo-elemento estiliza uma parte específica de um elemento em vez do todo, e usa um dois-pontos duplo (::) para distingui-lo de uma pseudo-classe de dois-pontos simples. Os mais usados são ::before e ::after, que criam um filho gerado no próprio início ou fim de um elemento. Eles requerem uma propriedade content para renderizar, mesmo que seja vazia (content: ""), e esse conteúdo gerado é decorativo: leitores de tela podem pular, então nunca coloque significado lá.

Outro comum é ::placeholder, que estiliza o texto de dica fraco dentro de uma entrada vazia. Porque pseudo-elementos apontam para uma fatia do elemento, eles permitem que você construa pequenas peças visuais (um ícone antes de um rótulo, uma linha decorativa após um título) sem adicionar tags extras ao seu markup.

Um pseudo-elemento expõe uma parte de um elemento que não tem sua própria tag, estilizado através de uma palavra-chave dois-pontos duplo. ::before e ::after geram uma caixa inline como o primeiro ou último filho do elemento; eles renderizam apenas quando content é definido (use content: "" para uma caixa puramente decorativa), e esse conteúdo gerado fica fora da árvore de acessibilidade, então deve permanecer decorativo e nunca carregar significado que um usuário precisa. ::placeholder aponta para o texto de dica de uma entrada, ::selection aponta para texto destacado, ::first-line e ::first-letter apontam para fatias tipográficas.

A história de dois-pontos simples versus duplos vale a pena conhecer. Pseudo-elementos modernos usam :: (dois dois-pontos) para separá-los de pseudo-classes, uma distinção introduzida no CSS3. Para os quatro pseudo-elementos originais (:before, :after, :first-line, :first-letter), a forma de dois-pontos simples ainda é analisada por razões legadas, mas escreva a forma de dois-pontos duplos; o dois-pontos simples é uma relíquia de compatibilidade, não um estilo que você deveria levar para código novo. Em produção, ::before e ::after fazem muito trabalho silencioso: dicas de ferramenta, marcadores de lista customizados, clearfix em layouts mais antigos, e floreios decorativos que de outra forma obscureceriam o HTML.

css
/* adicione uma seta decorativa após cada link nav */
.nav a::after {
  content: " →";
  color: rebeccapurple;
}

/* estilize o texto de dica dentro de uma caixa de busca */
.search-input::placeholder {
  color: grey;
  font-style: italic;
}

A regra ::after insere uma seta que vive apenas na estilização, não no HTML, enquanto ::placeholder alcança dentro da entrada para estilizar texto que o navegador desenha para você. Ambas estilizam algo que você não poderia alcançar com um seletor simples. Se você está estilizando texto de dica e rótulos, o capítulo tipografia vai mais fundo no lado de texto.

JunoPseudo-elementos Um pseudo-elemento estiliza uma parte de um elemento ou adiciona um pequeno conteúdo, e usa dois dois-pontos, como ::before e ::after. Esses dois precisam de uma propriedade content para aparecer. O dois-pontos duplo é a forma rápida de distinguir um pseudo-elemento de uma pseudo-classe.
JunoPseudo-elementos Pseudo-elementos usam um dois-pontos duplo e estilizam uma fatia de um elemento: ::before, ::after, ::placeholder. Os dois primeiros precisam de um valor content, mesmo um "" vazio, e esse conteúdo é decorativo, então mantenha significado real no seu HTML. Eles o salvam de adicionar tags apenas para pendurar uma decoração.
JunoPseudo-elementos Escreva pseudo-elementos com dois dois-pontos; a forma de dois-pontos simples só sobrevive para os quatro originais como uma particularidade legada. Conteúdo de ::before e ::after vive fora da árvore de acessibilidade, então permanece decorativo e nunca carrega nada que um usuário precisa ler. Eles silenciosamente lidam com dicas de ferramenta, marcadores customizados, e floreios que de outra forma inchariam seu markup.

Especificidade: qual regra vence

Mais cedo ou mais tarde duas regras tentarão estilizar o mesmo elemento de formas diferentes. Uma diz que o texto é azul, outra diz que é vermelho. O navegador tem que escolher uma, e a forma como ele decide é chamada especificidade: o seletor mais específico vence.

A versão curta é uma ordem de força. Um seletor de id bate um seletor de classe, e um seletor de classe bate um seletor de tipo. Então se #header e .title definem ambos uma cor no mesmo elemento, o id vence. Quando duas regras são igualmente específicas, a escrita depois no arquivo vence.

Quando várias regras apontam para o mesmo elemento e definem a mesma propriedade, o navegador resolve o conflito com especificidade, um escore baseado nos tipos de seletores envolvidos. A ordem de mais forte para mais fraco é: estilos inline (um atributo style no elemento), depois ids, depois classes (e pseudo-classes e seletores de atributo), depois seletores de tipo (e pseudo-elementos). Um seletor mais específico vence independentemente da ordem de fonte; apenas quando a especificidade se iguala é que a regra posterior vence.

Essa é a razão prática para depender de classes e evitar ids para estilização. Se você estilizar com ids, uma regra de classe posterior não pode sobrescrevê-los, então você termina escalando. E !important, que você pode anexar a uma declaração para forçá-la a vencer sobre tudo, deve ser tratado como um último recurso: quebra a cascata normal e a única forma de bater um !important é outro !important, que é uma espiral que você não quer começar.

Especificidade é o algoritmo que o navegador usa para escolher entre declarações conflitantes. É computada como uma contagem de três partes, frequentemente escrita (a, b, c): a é o número de seletores id, b é o número de classe, atributo, e seletores pseudo-classe, e c é o número de seletores tipo e pseudo-elemento. As partes se comparam da esquerda para a direita, então qualquer id bate qualquer número de classes, e qualquer classe bate qualquer número de seletores de tipo. #header .title a marca (1, 1, 1); .nav .menu .item a marca (0, 3, 1); o primeiro vence no id sozinho. Atributos style inline ficam acima de toda especificidade de seletor, e !important (uma flag que você anexa a um valor para forçá-lo) sobrescreve até isso; o seletor universal * e combinadores não adicionam nada ao escore.

Duas ferramentas modernas mudam como você gerencia isso. :is() leva uma lista de seletores e corresponde se qualquer um deles fizer, mas toma a especificidade de seu argumento mais específico, então :is(#header, .title) herda o peso do id. :where() faz a mesma correspondência mas tem zero especificidade sempre, o que o torna a ferramenta para escrever estilos base de baixo peso que qualquer coisa pode sobrescrever. :has(), a pseudo-classe relacional, corresponde a um elemento que contém algo ("um .card que tem uma imagem", .card:has(img)) e toma a especificidade de seu argumento. A prática de manutenibilidade debaixo de tudo isso é manter a especificidade baixa e plana: prefira seletores de classe única, evite ids e !important, e use :where() para zerar o peso onde você quer que padrões cedam. Especificidade plana significa que uma regra posterior pode sempre vencer sendo posterior, que é a cascata funcionando para você em vez de contra você.

css
/* seletor de tipo, especificidade (0, 0, 1) */
p {
  color: grey;
}

/* seletor de classe, especificidade (0, 1, 0): este vence */
.intro {
  color: black;
}
html
<p class="intro">Este parágrafo é preto, porque a regra de classe supera a regra de tipo.</p>

Ambas as regras apontam para o parágrafo e ambas definem color, mas o seletor de classe é mais específico que o seletor de tipo, então o parágrafo é preto. Levantar ou abaixar um seletor na escada de especificidade é frequentemente tudo o que é necessário para resolver um conflito sem recorrer a ferramentas mais pesadas. O capítulo box model enfrenta a mesma cascata quando regras de espaçamento colidem.

JunoEspecificidade Quando duas regras competem pelo mesmo elemento, a mais específica vence: um id bate uma classe, e uma classe bate um seletor de tipo. Se são igualmente específicas, qualquer que venha por último no arquivo vence. Isso explica a maioria dos conflitos.
JunoEspecificidade A força corre inline, depois id, depois classe, depois tipo, e uma regra mais específica vence não importa onde fica no arquivo. É por isso que estilizar com classes e evitar ids mantém seu CSS sobrescritível. Mantenha !important como um último recurso, porque a única coisa que bate um é outro.
JunoEspecificidade Especificidade conta como (a, b, c) para ids, classes, e tipos, comparado da esquerda para a direita, então um id supera qualquer pilha de classes. Mantenha baixo e plano: classes únicas, sem ids para estilização, sem !important, e :where() para zerar peso quando você quer que padrões cedam. Especificidade plana significa que uma regra posterior pode sempre vencer sendo posterior, e isso é a cascata funcionando com você.