The CSS Podcast - 015: Pseudo-classes
Suponha que você tenha um formulário de inscrição por e-mail e queira que o campo de e-mail tenha uma borda vermelha se contiver um endereço de e-mail inválido. Como fazer isso? Você pode usar uma pseudoclasse CSS :invalid
, que é uma das muitas pseudoclasses fornecidas pelo navegador.
Uma pseudoclasse permite aplicar estilos com base em mudanças de estado e fatores externos. Isso significa que seu design pode reagir à entrada do usuário, como um endereço de e-mail inválido. Eles são abordados no módulo seletores, e este módulo vai explicar cada um deles com mais detalhes.
Ao contrário dos pseudoelementos, que você pode conhecer melhor no módulo anterior, as pseudoclasses se conectam a estados específicos em que um elemento pode estar, em vez de estilizar partes desse elemento de maneira geral.
Estados interativos
As pseudoclasses a seguir são aplicadas devido a uma interação do usuário com sua página.
:hover
Se um usuário tiver um dispositivo apontador, como um mouse ou trackpad, e o colocar sobre um elemento, você poderá se conectar a esse estado com :hover
para aplicar estilos. Essa é uma maneira útil de sugerir que um elemento pode ser interagido.
:active
Esse estado é acionado quando um elemento está sendo interagido ativamente, como um clique, antes que o clique seja liberado. Se um dispositivo apontador, como um mouse, for usado, esse estado será quando o clique começar e ainda não tiver sido liberado.
:focus
, :focus-within
e :focus-visible
Se um elemento puder receber foco, como um <button>
, você poderá reagir a esse estado com a pseudoclasse :focus
.
Você também pode reagir se um elemento filho do seu elemento receber foco com :focus-within
.
Elementos focalizáveis, como botões, mostram um anel de foco quando estão em foco, mesmo quando clicados. Nesse tipo de situação, um desenvolvedor aplica o seguinte CSS:
button:focus { outline: none; }
Esse CSS remove o anel de foco padrão do navegador quando um elemento recebe foco, o que apresenta um problema de acessibilidade para usuários que navegam em uma página da Web com um teclado. Se não houver um estilo de foco, o usuário não conseguirá acompanhar onde o foco está no momento ao usar a tecla Tab. Com :focus-visible
é possível apresentar um estilo de foco quando um elemento recebe foco usando o teclado, além de usar a regra outline: none
para evitar isso quando um dispositivo de ponteiro interage com ele.
button:focus { outline: none; } button:focus-visible { outline: 1px solid black; }
:target
A pseudoclasse :target
seleciona um elemento que tem um id
correspondente a um fragmento de URL. Suponha que você tenha o seguinte HTML:
<article id="content"> <!-- ... --> </article>
É possível anexar estilos a esse elemento quando o URL contém #content
.
#content:target { background: yellow; }
Isso é útil para destacar áreas que podem ter sido vinculadas especificamente, como o conteúdo principal de um site, usando um link de navegação.
Estados históricos
:link
A pseudoclasse :link
pode ser aplicada a qualquer elemento <a>
que tenha um valor href
que ainda não foi visitado.
:visited
É possível estilizar um link que já foi visitado pelo usuário usando a pseudoclasse :visited
. Esse é o estado oposto a :link
, mas você tem menos propriedades de CSS para usar por motivos de segurança. Só é possível estilizar color
, background-color
, border-color
, outline-color
e a cor dos elementos SVG fill
e stroke
.
A ordem é importante
Se você definir um estilo :visited
, ele poderá ser substituído por uma pseudoclasse de link com especificidade pelo menos igual. Por isso, recomendamos que você use a regra LVHA para estilizar links com pseudoclasses em uma ordem específica: :link
, :visited
, :hover
, :active
.
a:link {} a:visited {} a:hover {} a:active {}
Estados do formulário
As pseudoclasses a seguir podem selecionar elementos de formulário nos vários estados em que esses elementos podem estar durante a interação.
:disabled
e :enabled
Se um elemento de formulário, como um <button>
, for desativado pelo navegador, você poderá se conectar a esse estado com a pseudoclasse :disabled
. A pseudoclasse :enabled
está disponível para o estado oposto, embora os elementos de formulário também sejam :enabled
por padrão, portanto, talvez você não precise usar essa pseudoclasse.
:checked
e :indeterminate
A pseudoclasse :checked
está disponível quando um elemento de formulário compatível, como uma caixa de seleção ou um botão de opção, está marcado.
O estado :checked
é binário (verdadeiro ou falso), mas as caixas de seleção têm um estado intermediário quando não estão marcadas nem desmarcadas. Esse é o estado :indeterminate
.
Um exemplo desse estado é quando você tem um controle "Selecionar tudo" que marca todas as caixas de seleção em um grupo. Se o usuário desmarcar uma dessas caixas de seleção, a caixa de seleção raiz não representará mais "tudo" marcado e, portanto, deverá ser colocada em um estado indeterminado.
O elemento <progress>
também tem um estado indeterminado que pode ser estilizado. Um caso de uso comum é dar a ele uma aparência listrada para indicar que não se sabe quanto mais é necessário.
:placeholder-shown
Se um campo de formulário tiver um atributo placeholder
e nenhum valor, a pseudoclasse :placeholder-shown
poderá ser usada para anexar estilos a esse estado. Assim que houver conteúdo no campo, com ou sem um placeholder
, esse estado não será mais aplicado.
Estados de validação
Você pode responder à validação de formulários HTML com pseudoclasses como :valid
, :invalid
e :in-range
. As pseudoclasses :valid
e :invalid
são úteis em contextos como um campo de e-mail que tem um pattern
que precisa ser correspondido para ser um campo válido. Esse estado de valor válido pode ser mostrado ao usuário, ajudando-o a entender que pode passar para o próximo campo com segurança.
A pseudoclasse :in-range
está disponível se uma entrada tiver um min
e um max
, como uma entrada numérica e o valor estiver dentro desses limites.
Com formulários HTML, é possível determinar que um campo é obrigatório com o atributo required
. A pseudoclasse :required
estará disponível para campos obrigatórios. Os campos que não são obrigatórios podem ser selecionados com a pseudoclasse :optional
.
Como selecionar elementos por índice, ordem e ocorrência
Há um grupo de pseudoclasses que selecionam itens com base em onde eles estão no documento.
:first-child
e :last-child
Se quiser encontrar o primeiro ou o último item, use :first-child
e :last-child
. Essas pseudoclasses retornam o primeiro ou o último elemento em um grupo de elementos irmãos.
:only-child
Também é possível selecionar elementos que não têm irmãos com a pseudoclasse :only-child
.
:first-of-type
e :last-of-type
Você pode selecionar :first-of-type
e :last-of-type
, que, a princípio, parecem fazer a mesma coisa que :first-child
e :last-child
, mas considere este HTML:
<div class="my-parent"> <p>A paragraph</p> <div>A div</div> <div>Another div</div> </div>
E este CSS:
.my-parent div:first-child { color: red; }
Nenhum elemento seria colorido de vermelho porque o primeiro filho é um parágrafo e não uma div. A pseudoclasse :first-of-type
é útil nesse contexto.
.my-parent div:first-of-type { color: red; }
Mesmo que o primeiro <div>
seja o segundo filho, ele ainda é o primeiro do tipo dentro do elemento .my-parent
, portanto, com essa regra, ele será colorido de vermelho.
:nth-child
e :nth-of-type
Você não está limitado a primeiro e último filhos e tipos. As pseudoclasses :nth-child
e :nth-of-type
permitem especificar um elemento que está em um determinado índice. A indexação em seletores CSS começa em 1.
As pseudoclasses :nth-last-child()
e :nth-last-of-type()
contam do final, e não do início.
Você também pode transmitir mais de um índice para essas pseudoclasses. Se você quiser selecionar todos os elementos pares, use :nth-child(even)
.
Também é possível criar seletores mais complexos que encontram itens em intervalos regularmente espaçados usando a microssintaxe An+B.
li:nth-child(3n+3) { background: yellow; }
Esse seletor seleciona todos os itens a cada três, começando pelo item 3. O n
nessa expressão é o índice, que começa em zero, e o 3 (3n
) é o valor pelo qual você multiplica esse índice.
Digamos que você tenha sete itens <li>
. O primeiro item selecionado é 3 porque 3n+3
é traduzido como (3 * 0) + 3
. A próxima iteração escolheria o item 6 porque n
agora foi incrementado para 1
, então (3 * 1) + 3)
. Essa expressão funciona para :nth-child
e :nth-of-type
.
:nth-child()
e :nth-last-child()
também oferecem suporte a uma sintaxe "de S" que permite filtrar as correspondências com um seletor, semelhante a :nth-of-type()
. li:nth-of-type(even)
é equivalente a :nth-child(even of li)
. Enquanto :nth-of-type
permite filtrar apenas com base no tipo de elemento (como li
ou p
), a sintaxe "de S" permite filtrar qualquer seletor.
Se você tiver uma tabela, talvez queira adicionar listras a cada outra linha. Embora seja possível segmentar todas as outras linhas com tr:nth-child(even)
, isso não funciona se você estiver filtrando algumas linhas. Se você implementar a filtragem aplicando o atributo hidden
, adicione of :not([hidden])
ao seletor para pré-filtrar os itens ocultos antes de selecionar as linhas pares.
tr:nth-child(even of :not([hidden])){ background: lightgrey; }
Você pode testar esse tipo de seletor neste teste de nth-child ou nesta ferramenta de seletor de quantidade.
:only-of-type
Por fim, é possível encontrar o único elemento de um determinado tipo em um grupo de irmãos com :only-of-type
. Isso é útil se você quiser selecionar listas com apenas um item ou encontrar o único elemento em negrito em um parágrafo.
Encontrar elementos vazios
Às vezes, é útil identificar elementos completamente vazios, e há uma pseudoclasse para isso também.
:empty
Se um elemento não tiver filhos, a pseudoclasse :empty
será aplicada a ele. No entanto, os filhos não são apenas elementos HTML ou nós de texto: eles também podem ser espaços em branco, o que pode ser confuso ao depurar o seguinte HTML e se perguntar por que ele não está funcionando com :empty
:
<div> </div>
O motivo é que há um espaço em branco entre as tags de abertura e fechamento <div>
. Por isso, :empty
não vai funcionar.
A pseudoclasse :empty
pode ser útil se você tiver pouco controle sobre o HTML e quiser ocultar elementos vazios, como um editor de conteúdo WYSIWYG. Aqui, um editor adicionou um parágrafo vazio perdido.
<article class="post"> <p>Donec ullamcorper nulla non metus auctor fringilla.</p> <p></p> <p>Curabitur blandit tempus porttitor.</p> </article>
Com o :empty
, você pode encontrar e ocultar esse conteúdo.
.post :empty { display: none; }
Encontrar e excluir vários elementos
Algumas pseudoclasses ajudam você a escrever CSS mais compacto.
:is()
Se você quiser encontrar todos os elementos filhos h2
, li
e img
em um elemento .post
, pode pensar em escrever uma lista de seletores assim:
.post h2, .post li, .post img { … }
Com a pseudoclasse :is()
, é possível escrever uma versão mais compacta:
.post :is(h2, li, img) { /* ... */ }
A pseudoclasse :is
não é apenas mais compacta do que uma lista de seletores, mas também mais tolerante. Na maioria dos casos, se houver um erro ou um seletor não compatível em uma lista de seletores, toda a lista deixará de funcionar. Se houver um erro nos seletores transmitidos em uma pseudoclasse :is
, o seletor inválido será ignorado, mas os válidos serão usados.
:not()
Também é possível excluir itens com a pseudoclasse :not()
. Por exemplo, você pode usar esse seletor para estilizar todos os links que não têm um atributo class
.
a:not([class]) { color: blue; }
Uma pseudoclasse :not
também pode ajudar a melhorar a acessibilidade. Por exemplo, um <img>
precisa ter um alt
, mesmo que seja um valor vazio. Assim, você pode escrever uma regra CSS que adicione um contorno vermelho grosso a imagens inválidas:
img:not([alt]) { outline: 10px red; }
:has()
E se você quiser estilizar elementos com base no que está contido neles? Para isso, use a pseudoclasse :has()
. Por exemplo, talvez você queira aplicar estilos a botões que incluem ícones.
button:has(svg) { /* ... */ }
Na configuração mais básica, como no exemplo anterior, é possível pensar em :has()
como um seletor principal. Você também pode usar o seletor de correspondência de elemento pai combinado com outros seletores para segmentar outros elementos.
form:has(input:valid) label { font-weight: bold; } form:has(input:valid) label::after { content: "✅"; }
Neste exemplo, estamos aplicando estilos ao elemento de rótulo e ao pseudoelemento label::after
quando a entrada do formulário tem uma pseudoclasse valid
.
A pseudoclasse :has()
não pode ser aninhada em outra :has()
, mas pode ser combinada com outras pseudoclasses.
:is(h1, h2, h3):has(a) { /* ... */ }
A lista de seletores é implacável. Se algum seletor na lista for inválido, todas as regras de estilo serão ignoradas.
.my-element:has(img, ::before) { /* any styles here will be discarded since pseudo elements can't be included in the :has() selector list */ }
Teste seu conhecimento
Teste seus conhecimentos sobre pseudoclasses
As pseudoclasses agem como se uma classe tivesse sido aplicada dinamicamente a um elemento, enquanto os pseudoelementos agem no próprio elemento.
:
como um caractere de distinção principal no seletor.Qual das opções a seguir é uma pseudoclasse funcional?
:is()
:target
()
depois delas para indicar que aceitam parâmetros.:empty
()
depois delas para indicar que aceitam parâmetros.:not()
Qual das seguintes pseudoclasses é resultado de uma interação do usuário?
:hover
:press
:squeeze
:target
:focus-within
Quais das seguintes opções são pseudoclasses de estado <form>
?
:enabled
:fresh
:indeterminate
:checked
:in-range
:loading
:valid