Estilizando Estados Válidos e Inválidos de Formulários com CSS
Campos obrigatórios vazios brilhando em vermelho antes que os usuários digitem um único caractere. Essa é a experiência frustrante que muitos formulários oferecem—e é totalmente evitável com CSS moderno.
Este guia aborda estados de validação de formulários CSS e as pseudo-classes que os controlam. Você aprenderá quando usar :valid e :invalid, por que :user-valid e :user-invalid proporcionam melhor UX, e como estilizar erros de formulário com CSS usando padrões como :has() para estilização de elementos pai.
Principais Conclusões
- A validação de restrições HTML5 funciona automaticamente com atributos como
required,type,min,maxepattern - Evite
:valide:invalidpara estilização de erros, pois são acionados antes da interação do usuário - Use
:user-valide:user-invalidpara mostrar feedback de validação apenas após os usuários interagirem com os campos - Combine
:has()com pseudo-classes de validação para estilizar elementos pai e controlar a visibilidade de mensagens de erro - Sempre combine validação visual com atributos ARIA para acessibilidade de leitores de tela
Como Funciona a Validação de Restrições
A validação de restrições HTML5 acontece automaticamente. Quando você adiciona atributos como required, type="email", min, max, minlength, maxlength ou pattern aos campos de formulário, os navegadores avaliam a validade continuamente.
O navegador verifica as restrições sempre que o valor do input muda. As pseudo-classes CSS refletem esse estado de validade em tempo real, permitindo que você estilize campos com base em se eles passam ou falham na validação.
<input type="email" required minlength="5" />
Este campo se torna inválido se estiver vazio, se o valor não estiver formatado como e-mail, ou se for menor que cinco caracteres.
Pseudo-Classes Principais de Formulários CSS
:valid e :invalid
Essas pseudo-classes correspondem a campos com base na validade atual:
input:valid {
border-color: green;
}
input:invalid {
border-color: red;
}
O problema: :invalid se aplica imediatamente no carregamento da página. Um campo obrigatório sem valor é tecnicamente inválido antes que o usuário o toque. Isso cria uma experiência ruim—os usuários veem erros antes de terem feito algo errado.
:required e :optional
Essas segmentam campos com base no atributo required:
input:required {
border-left: 3px solid blue;
}
input:optional {
border-left: 3px solid gray;
}
Útil para indicadores visuais mostrando quais campos devem ser preenchidos.
:in-range e :out-of-range
Para inputs de número e intervalo com restrições min/max:
input:in-range {
background: white;
}
input:out-of-range {
background: #ffe0e0;
}
Melhor UX com :user-valid e :user-invalid
As pseudo-classes :user-valid e :user-invalid resolvem o problema de erro prematuro. Elas só correspondem após o usuário ter interagido com o campo—tipicamente após editar e desfocar.
input:user-invalid {
border-color: red;
}
input:user-valid {
border-color: green;
}
Agora os campos obrigatórios não mostram erros no carregamento da página. A estilização de validação aparece apenas após os usuários terem tido a chance de inserir dados. Isso corresponde às expectativas do usuário e reduz a frustração.
Essas pseudo-classes têm amplo suporte de navegadores e devem ser sua escolha padrão para estilizar erros de formulário com CSS.
Discover how at OpenReplay.com.
Estilização de Elementos Pai com :has()
O seletor :has() permite estilizar elementos pai com base nos estados de validação dos filhos—algo anteriormente impossível sem JavaScript.
<div class="field">
<label for="email">Email</label>
<input type="email" id="email" required />
<span class="error">Por favor, insira um email válido</span>
</div>
.error {
display: none;
color: red;
}
.field:has(input:user-invalid) .error {
display: block;
}
.field:has(input:user-invalid) input {
border-color: red;
}
Este padrão mostra mensagens de erro apenas quando o input contido falha na validação após a interação do usuário. O contêiner pai controla a visibilidade de elementos de erro irmãos.
Considerações de Acessibilidade
A estilização visual sozinha não é suficiente para formulários acessíveis. Usuários de leitores de tela precisam de associações de erro programáticas.
Combine estados de validação CSS com atributos ARIA apropriados:
<div class="field">
<label for="email">Email</label>
<input
type="email"
id="email"
required
aria-describedby="email-error"
aria-invalid="false"
/>
<span id="email-error" class="error" aria-live="polite">
Por favor, insira um email válido
</span>
</div>
Requisitos principais de acessibilidade:
aria-describedbyvincula o input à sua mensagem de erroaria-live="polite"anuncia mudanças de erro aos leitores de telaaria-invaliddeve ser atualizado via JavaScript quando a validação falhar- Contraste de cores deve atender aos requisitos WCAG (4.5:1 para texto)
- Não confie apenas na cor—use ícones ou texto junto com mudanças de cor
Padrão Prático: Validação Completa de Campo
Aqui está um padrão pronto para produção combinando essas técnicas:
/* Estilos base do campo */
.field input {
border: 2px solid #ccc;
transition: border-color 0.2s;
}
/* Estado válido após interação */
.field:has(input:user-valid) input {
border-color: #2e7d32;
}
/* Estado inválido após interação */
.field:has(input:user-invalid) input {
border-color: #c62828;
}
.field:has(input:user-invalid) .error {
display: block;
}
/* Mensagem de erro oculta por padrão */
.error {
display: none;
color: #c62828;
font-size: 0.875rem;
margin-top: 0.25rem;
}
Esta abordagem mantém as mensagens de erro ocultas até que os usuários interajam com os campos, revelando-as apenas quando a validação falha.
Conclusão
As pseudo-classes modernas de formulários CSS fornecem estilização de validação poderosa sem JavaScript. Use :user-valid e :user-invalid como suas ferramentas principais—elas previnem exibição prematura de erros e correspondem às expectativas do usuário. Combine-as com :has() para estilização em nível de pai que controla a visibilidade de mensagens de erro.
Lembre-se de que a estilização visual complementa, mas não substitui, o tratamento de erros acessível. Sempre combine estados de validação CSS com atributos ARIA apropriados para usuários de leitores de tela.
Perguntas Frequentes
A pseudo-classe :invalid corresponde a qualquer campo que falhe na validação, incluindo no carregamento da página antes da interação do usuário. A pseudo-classe :user-invalid só corresponde após o usuário ter interagido e saído do campo. Isso evita mostrar estilos de erro em campos obrigatórios vazios antes que os usuários tenham a chance de preenchê-los.
Essas pseudo-classes têm amplo suporte em navegadores modernos, incluindo Chrome, Firefox, Safari e Edge. Para suporte a navegadores mais antigos, considere usar as pseudo-classes :focus e :not(:placeholder-shown) como padrão alternativo, embora essa abordagem seja menos precisa.
As pseudo-classes de validação CSS refletem o estado da API de validação de restrições do navegador. Se você prevenir o envio padrão do formulário ou usar JavaScript para lidar com formulários, certifique-se de chamar checkValidity() nos elementos do formulário. Os estados CSS são atualizados com base na propriedade validity, não em tentativas de envio.
Use o seletor :has() em um contêiner pai para detectar estados de validação de input filho. Por exemplo, .field:has(input:user-invalid) .error-message permite que você mostre ou oculte elementos de erro irmãos com base em se o input dentro desse contêiner falha na validação após a interação do usuário.
Truly understand users experience
See every user interaction, feel every frustration and track all hesitations with OpenReplay — the open-source digital experience platform. It can be self-hosted in minutes, giving you complete control over your customer data. . Check our GitHub repo and join the thousands of developers in our community..