⚡ Curso de CSS • Web-ZoneWare

Pseudo-classes no CSS: hover, focus e visible | Web Academy

Lição 39 de 50

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.

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).

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):

CSS3 21 linhas
/* 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 Tab do teclado ou um leitor de tela: o navegador ativa :focus-visible e exibe um anel de foco destacado!
CSS3 6 linhas
/* 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:

CSS3 5 linhas
/* 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:

HTML5 112 linhas
<!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:

⚡ Abrir no Playground IDE →

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, :hover e :active.
  • Nunca use outline: none sem fornecer um substituto de alta visibilidade!
  • :focus-visible exibe anéis de foco exclusivamente na navegação por teclado (Tab) e leitores de tela, mantendo cliques de mouse limpos.
  • :focus-within estiliza o elemento pai quando qualquer nó filho recebe foco.
  • :valid e :invalid permitem 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)!

Rolar para cima