Pseudo-classes no CSS: hover, focus e visible | Web Academy
Uma página web onde os elementos não reagem às ações do usuário parece estática e desprovida de vida. No CSS, o que transforma um simples documento de marcação em uma interface digital tátil e responsiva são as Pseudo-classes (identificadas por um único caractere de dois pontos :). Elas permitem aplicar regras de estilo condicionadas ao estado dinâmico de um elemento: passar o cursor por cima, pressionar um botão, selecionar um campo com a tecla Tab ou validar um formulário. Nesta lição, você dominará o ciclo de vida dos links (regra LVHA), a revolução de acessibilidade do :focus-visible e os estados de formulário modernos.
📑 Índice do Conteúdo
1. O que é uma Pseudo-classe?
Enquanto um seletor comum (como .botao) mira o elemento em seu estado estático padrão, uma pseudo-classe visa o elemento em uma circunstância temporal ou comportamental transitória.
Diferença Essencial de Sintaxe:
- Pseudo-classe (1 caractere
:): Reflete um estado dinâmico do elemento inteiro (ex.::hover,:focus,:checked). - Pseudo-elemento (2 caracteres
::): Cria ou estiliza uma parte interna específica do elemento (ex.:::before,::after,::placeholder).
2. O Ciclo de Vida dos Links e a Regra LVHA (LoVe HAte)
Ao estilizar links de navegação, a ordem em que você escreve as regras no arquivo CSS não é opcional — ela é ditada pela cascata de especificidade do navegador. Se você inverter a ordem, um estado pode anular o outro silenciosamente.
Para nunca errar, memorize o mnemônico mundial da web: LoVe HAte (Link, Visited, Hover, Active):
/* 1. L (Link): Estado virgem (não visitado) */
a:link {
color: #38bdf8;
text-decoration: none;
}
/* 2. V (Visited): Link já clicado pelo usuário anteriormente */
a:visited {
color: #a855f7;
}
/* 3. H (Hover): O ponteiro do mouse repousa sobre o link */
a:hover {
color: #60a5fa;
text-decoration: underline;
}
/* 4. A (Active): O exato instante em que o clique está pressionado */
a:active {
color: #ef4444;
}
3. O Duelo de Acessibilidade: :focus vs. :focus-visible
Durante décadas, designers gráficos e desenvolvedores cometeram o maior crime contra a acessibilidade na web: aplicar outline: none; ou outline: 0; para eliminar a borda azul nativa do navegador que aparecia quando um botão era clicado com o mouse.
O efeito colateral foi devastador: milhões de pessoas com deficiência motora que navegam exclusivamente pela tecla Tab ficaram cegas, sem saber onde o cursor estava na tela!
A Salvação: A Pseudo-classe :focus-visible
A W3C resolveu esse conflito histórico criando a pseudo-classe :focus-visible:
- Se o usuário clicar no botão com o mouse ou tocar na tela do celular: nenhum anel de foco é exibido (design limpo!).
- Se o usuário navegar usando a tecla
Tabdo teclado ou um leitor de tela: o navegador ativa:focus-visiblee exibe um anel de foco destacado!
/* Padrão de Alta Acessibilidade e Design Impecável */
button:focus-visible,
a:focus-visible {
outline: 2px solid #38bdf8;
outline-offset: 4px; /* Afasta o anel das bordas arredondadas com elegância */
}
4. O Efeito Cascata do :focus-within
A pseudo-classe :focus-within possui um comportamento genial: ela seleciona um elemento contêiner pai se qualquer elemento filho dentro dele receber foco!
É a técnica perfeita para acender a borda de um cartão de formulário ou escurecer o fundo quando o usuário clica em qualquer campo de texto interno:
/* O cartão inteiro ganha uma borda azul e sombra quando o usuário foca no input */
.cartao-login:focus-within {
border-color: #38bdf8;
box-shadow: 0 0 20px rgba(56, 189, 248, 0.2);
}
5. Estados Interativos de Formulários
O CSS moderno permite validar e reagir a campos de formulário sem precisar de uma única linha de JavaScript:
| Pseudo-classe | Condição de Ativação | Exemplo de Uso |
|---|---|---|
:disabled |
O elemento possui o atributo disabled. |
Botões cinzas sem clique (cursor: not-allowed; opacity: 0.5). |
:checked |
Caixa de seleção (checkbox) ou rádio marcada. | Criação de botões toggle e switches personalizados no CSS. |
:valid |
O valor digitado atende aos requisitos do campo. | Exibir uma borda verde suave quando o e-mail for válido. |
:invalid |
O valor viola regras de tipo, formato ou required. |
Borda vermelha e aviso quando o campo estiver incorreto. |
:placeholder-shown |
O texto do placeholder ainda está visível. | Efeito de rótulo flutuante (Floating Label) ao digitar. |
6. Laboratório Prático: Formulário Reativo e Foco Acessível
No código interativo abaixo, experimente navegar usando a tecla Tab para ver o anel do :focus-visible com outline-offset, observe o cartão reagindo com :focus-within e teste digitar um e-mail para ver a validação em tempo real com :valid:
<!DOCTYPE html>
<html lang="pt-BR">
<head>
<meta charset="UTF-8">
<title>Laboratório de Pseudo-classes CSS</title>
<style>
body {
font-family: 'Inter', system-ui, sans-serif;
background: #0b0f19;
color: #f8fafc;
padding: 40px;
margin: 0;
}
/* 1. O PAI REAGE COM :focus-within */
.formulario-card {
max-width: 420px;
background: #1e293b;
border: 1px solid #334155;
border-radius: 14px;
padding: 24px;
transition: border-color 0.3s ease, box-shadow 0.3s ease;
}
.formulario-card:focus-within {
border-color: #38bdf8;
box-shadow: 0 8px 30px rgba(56, 189, 248, 0.15);
}
.campo-grupo {
margin-bottom: 20px;
}
label {
display: block;
font-size: 0.85rem;
color: #94a3b8;
margin-bottom: 8px;
font-weight: 600;
}
/* 2. ESTADOS DO INPUT (:valid e :invalid) */
.input-texto {
width: 100%;
background: #0f172a;
border: 1px solid #334155;
border-radius: 8px;
padding: 12px 14px;
color: #f8fafc;
font-size: 1rem;
box-sizing: border-box;
outline: none;
transition: border-color 0.2s ease;
}
.input-texto:focus {
border-color: #38bdf8;
}
.input-texto:not(:placeholder-shown):valid {
border-color: #10b981; /* Borda verde quando válido! */
}
.input-texto:not(:placeholder-shown):invalid {
border-color: #ef4444; /* Borda vermelha se formato inválido! */
}
/* 3. BOTÃO COM :hover, :active E :focus-visible */
.btn-enviar {
width: 100%;
background: #2563eb;
color: #fff;
border: none;
border-radius: 8px;
padding: 14px;
font-size: 1rem;
font-weight: 700;
cursor: pointer;
transition: background 0.2s ease, transform 0.1s ease;
}
.btn-enviar:hover {
background: #1d4ed8;
}
.btn-enviar:active {
transform: scale(0.98); /* Feedback tátil ao clicar */
}
/* ACESSIBILIDADE POR TECLADO (TAB) */
.btn-enviar:focus-visible {
outline: 2px solid #38bdf8;
outline-offset: 4px;
}
</style>
</head>
<body>
<div class="formulario-card">
<h3 style="margin-top:0; color:#f1f5f9;">Acesso ao Portal</h3>
<p style="color:#64748b; font-size:0.85rem; margin-bottom:20px;">
Navegue usando o <kbd>Tab</kbd> do teclado para ver o <code>:focus-visible</code> em ação!
</p>
<div class="campo-grupo">
<label for="email">E-mail Corporativo</label>
<input type="email" id="email" class="input-texto" placeholder="[email protected]" required>
</div>
<button type="button" class="btn-enviar">Entrar no Ambiente →</button>
</div>
</body>
</html>
Abra este laboratório no Playground IDE e teste clicar no formulário para comprovar o :focus-within no contêiner e a validação de e-mail dinâmica sem JavaScript:
7. Resumo e Próximos Passos
- Pseudo-classes (com
:) estilizam elementos com base no seu estado dinâmico ou comportamental. - A ordem dos links deve seguir estritamente o mnemônico LVHA:
:link,:visited,:hovere:active. - Nunca use
outline: nonesem fornecer um substituto de alta visibilidade! :focus-visibleexibe anéis de foco exclusivamente na navegação por teclado (Tab) e leitores de tela, mantendo cliques de mouse limpos.:focus-withinestiliza o elemento pai quando qualquer nó filho recebe foco.:valide:invalidpermitem criar feedbacks visuais imediatos em formulários HTML5.
A Conclusão do Módulo 4 Está Próxima: Além dos estados do usuário, como selecionar o primeiro filho de uma lista, zebrar tabelas alternadas a cada duas linhas ou ignorar certos nós? Na Lição 40, fecharemos o Módulo 4 dominando as Pseudo-classes Estruturais (:nth-child, :first-child, :last-child, :not e :empty)!