Validando formulários com HTML e CSS
Formulários são a forma padrão que usamos para permitir que usuários do nosso site tenham algum tipo de interação. Desde o HTML5 e CSS3 os formulários melhoraram bastante, com a disponibilidade de diversos tipos de campos e a possibilidade de validar o preenchimento desses campos sem a necessidade de grandes intervenções do JavaScript.
Um formulário de contatos simples.
Apesar de já estarmos vivendo na era das IAs, JavaScript ainda é um grande calcanhar de aquiles para quem começa a desenvolver páginas para a Web. A linguagem é bem complexa e tem muitas estruturas e paradigmas diferentes de outras linguagens, até porque, é a linguagem de programação padrão para interagir diretamente com o navegador do usuário.
Talvez seja por isso que muitos ingressantes no desenvolvimento confundem "frameworks" como Angular, React e Bootstrap com linguagens. Mas eles são apenas "caminhos mais curtos" para desenvolver com JavaScript.
Um formulário de contatos
Para começar a desenvolver formulários HTML5 mais fáceis de validar, vamos à prática. Vamos montar um formulário de contatos bem simples, mas funcional (pelo menos no front-end).
Como requisitos, vamos usar, obviamente HTML5, CSS3 para estilizar a coisa toda e só um pouco de JavaScript para corrigir algumas limitações do HTML5, mas esse último é opcional e pode ser completamente removido.
Começamos pelo código HTML:
<!DOCTYPE html>
<html lang="pt-br">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<!-- Carrega o CSS do tema do site -->
<link rel="stylesheet" href="style.css">
<!-- Carrega o CSS específico desta página -->
<link rel="stylesheet" href="contact.css">
<title>Meu Site - Faça contato</title>
</head>
<body>
<div id="wrap">
<header>
<h1>📰 Meu Site</h1>
</header>
<nav>
<a href="index.html">Início</a>
<a href="contatos.html">Contatos</a>
<a href="sobre.html">Sobre</a>
</nav>
<main>
<article>
<h2>Faça contato</h2>
<div id="formBlock">
<p>Preencha todos os campos para entrar em contato conosco.</p>
<p class="fillalert">* Todos os campos são obrigatórios.</p>
<form method="post" name="contact" action="#sended" id="formContact">
<input type="hidden" name="meta" value="{ 'meta1': 'metadata1', 'meta2': 'metadata2' }">
<p>
<label for="fieldName">Nome:</label>
<input type="text" name="name" id="fieldName" placeholder="Seu nome completo" required minlength="2">
</p>
<p>
<label for="fieldEmail">E-mail:</label>
<input type="email" name="email" id="fieldEmail" placeholder="Seu e-mail" required>
</p>
<p>
<label for="fieldSubject">Assunto:</label>
<input type="text" name="subject" id="fieldSubject" placeholder="Assunto do contato" required minlength="3">
</p>
<p>
<label for="fieldMessage">Mensagem:</label>
<textarea name="message" id="fieldMessage" placeholder="Sua mensagem" required minlength="4"></textarea>
</p>
<p>
<button type="submit">Enviar</button>
<small>← Clique somente uma vez!</small>
</p>
</form>
</div>
</article>
<aside>
<h3>Veja mais...</h3>
<p>Lorem ipsum dolor, sit amet consectetur adipisicing elit.</p>
</aside>
</main>
<footer>© Copyright 2024 Eu mesmo</footer>
</div>
<script src="script.js"></script>
</body>
</html>
Nesse código, a validação é configurada nos campos do formulário, por exemplo, observe o campo "Nome:":
<input
type="text"
name="name"
id="fieldName"
placeholder="Seu nome completo"
required
minlength="2"
>
- O atributo
required
especifica que este campo deve ser preenchido para que o formulário seja enviado; - O atributo
minlength="2"
especifica que este campo deve ser preenchido com pelo menos 2 caracteres.
Já no campo "E-mail:":
<input
type="email"
name="email"
id="fieldEmail"
placeholder="Seu e-mail"
required
>
Aqui, além do required
que já usamos, estamos especificando que este campo só aceita um endereço de e-mail válido por conta da definição do tipo em type="email"
. Essa obrigatoriedade ocorre porque este tipo de campo valida a inserção usando uma Regex. Para saber mais sobre isso, fiz este artigo.
Os outros campos seguem a mesma premissa. O campo "Assunto:" é um type="text"
, daí usamos required
para torná-lo obrigatório e minlength="3"
para que este seja preenchido com pelo menos 3 caracteres:
<input
type="text"
name="subject"
id="fieldSubject"
placeholder="Assunto do contato"
required
minlength="3"
>
O campo "Mensagem:" é do tipo textarea
, mas os atributos são os mesmos:
<textarea
name="message"
id="fieldMessage"
placeholder="Sua mensagem"
required
minlength="4"
></textarea>
Dependendo do tipo de campo e do tipo de informação que você quer validar, diversos outros atributos podem ser usados, por exemplo:
maxlength
especifica o número máximo de caracteres permitidos em um campo de entrada;min
emax
especificam valores mínimo e máximo para um campo de entrada numérico comonumber
,date
,time
, etc.pattern
especifica uma Regex com a qual o valor do campo de entrada é verificado quando o formulário é enviado.
O tipo de campo e de dado a ser inserido também interfere nessa validação. O HTML5 traz mais de 25 tipos de campos diferentes que podem ser usados em formulários, para inserção dos mais diversos tipos de dados específicos.
Se quiser se aprimorar em formulários HTML5, sugiro que comece aqui.
Melhorando e validando visualmente
Como disse antes, a validação HTML5 pode ser complementada pelo CSS, usando as pseudo tags :valid
e :invalid
. Basicamente, podemos alterar estilos de um elemento conforme a validade deste, obtida do HTML5.
Para nosso formulário, escrevi o CSS abaixo como um exemplo:
/**
* Folhas de estilo do formulário de contatos.
**/
/* Variáveis */
:root {
/* Elementos inválidos. */
--invalid-background-color: rgb(255, 230, 230);
--invalid-border-color: rgb(255, 0, 0);
--invalid-botton-background: rgb(150, 150, 150);
/* Elementos válidos. */
--valid-background-color: rgb(232, 240, 254);
--valid-border-color: rgb(70, 130, 180);
--valid-botton-background: rgb(70, 130, 180);
}
/* Preset dos campos e botão */
#formBlock input,
#formBlock textarea,
#formBlock button {
font-family: inherit;
font-size: inherit;
border: none;
border-radius: 0.35rem;
background-color: #eee;
}
#formBlock input,
#formBlock textarea {
padding: 0.5rem;
width: 100%;
}
#formBlock textarea {
height: 6rem;
resize: vertical;
}
#formBlock button {
color: #fff;
font-weight: bold;
padding: 0.5rem 1rem;
}
/* Outros componentes */
#formBlock form {
max-width: 500px;
margin: auto;
}
#formBlock .fillalert {
text-align: center;
color: rgb(255, 0, 0);
font-size: small;
font-style: italic;
}
#formBlock label {
display: block;
padding: 0 0 0.25rem 0.5rem;
}
#formBlock small {
font-size: 70%;
color: #888;
}
/* Formulário inválido */
#formBlock input:invalid,
#formBlock textarea:invalid {
background-color: var(--invalid-background-color);
border: 1px solid var(--invalid-border-color);
border-bottom: 3px solid var(--invalid-border-color);
border-right: 3px solid var(--invalid-border-color);
}
#formBlock form:invalid button {
background-color: var(--invalid-botton-background);
cursor: not-allowed;
pointer-events: none;
}
/* Formulário válido */
#formBlock input:valid,
#formBlock textarea:valid {
background-color: var(--valid-background-color);
border: 1px solid var(--valid-border-color);
border-bottom: 3px solid var(--valid-border-color);
border-right: 3px solid var(--valid-border-color);
}
#formBlock form:valid button {
background-color: var(--valid-botton-background);
cursor: pointer;
pointer-events: all;
}
O que temos de relevante aqui é o trecho que estiliza os campos quando estes estiverem inválidos:
#formBlock input:invalid,
#formBlock textarea:invalid {
...
}
Aqui especificamos os estilos para os campos de entrada de dados input
e textarea
.
O botão também tem a versão inválida onde o destaque é o atributo pointer-events: none;
que bloqueia cliques no botão:
#formBlock form:invalid button {
background-color: var(--invalid-botton-background);
cursor: not-allowed;
pointer-events: none;
}
Quando os campos são válidos, entra em ação a pseudo tag :valid
que aplica estilos visuais compatíveis com o preenchimento correto:
#formBlock input:valid,
#formBlock textarea:valid {
...
}
#formBlock form:valid button {
...
pointer-events: all;
}
No caso do botão, agora usamos pointer-events: all;
para permitir cliques no botão.
Limitações e soluções
Apesar da nossa validação "passiva" já estar funcionando, claro que, em se tratando de front-end, HTML e CSS podem não ser suficientes para uma solução completa.
Um problema que temos aqui: se você preencher um dos campos, exceto o de e-mail, somente com espaços, ele será validado, já que, espaços são caracteres válidos. Outro problema é o envio de códigos maliciosos como JavaScript por exemplo, que podem acabar comprometendo seu servidor.
Abaixo temos um JavaScript bem simples, mas com alguma capacidade de limitar esses problemas:
/**
* JavaScript para a página de contatos.
**/
// Sanitiza a string argumento
function stripTags(htmlText) {
let div = document.createElement('div');
div.innerHTML = htmlText.trim().replace(/<script>.*<\/script>/, '');
return div.textContent;
}
// Sanitiza os campos do formulário
function clearFields() {
// Referências dos elementos
var fieldName = document.getElementById('fieldName');
var fieldEmail = document.getElementById('fieldEmail');
var fieldSubject = document.getElementById('fieldSubject');
var fieldMessage = document.getElementById('fieldMessage');
// Sanitiza e reescreve os campos
fieldName.value = stripTags(fieldName.value);
fieldEmail.value = stripTags(fieldEmail.value);
fieldSubject.value = stripTags(fieldSubject.value);
fieldMessage.value = stripTags(fieldMessage.value);
}
// Quando o documento estiver pronto no navegador
document.addEventListener('DOMContentLoaded', function () {
// Referência do formulário de contatos
var formContact = document.getElementById('formContact');
// Se o formulário existe
if (formContact) {
// Quando o formulário for enviado, executa `clearFields`
formContact.addEventListener('submit', clearFields);
// Quando o formulário for modificado, executa `clearFields`
formContact.addEventListener('change', clearFields);
}
});
Mesmo para iniciantes, o código é bem simples e está bem comentado. Basicamente temos uma função stripTags()
que remove espaços e códigos HTML da string passada como argumento.
Em seguida, a função clearFields()
que aplica stripTags()
a cada campo do formulário.
Já apresentamos a função stripTags()
nesse artigo, junto com outras, bem úteis.
O trecho final monitora quando o formulário é modificado ou enviado e chama clearFields()
para sanitizar os campos. Se um campo tem somente espaços ou códigos inválidos, ele terá seu conteúdo apagado, tornando o formulário inválido novamente, sem ser enviado.
Você pode ver os códigos completos e funcionando, na íntegra, neste link, e ainda fazer seus próprios experimentos.
Formulário com campos válidos.
Observações para desatentos
O exemplo acima demonstra apenas a parte front-end da coisa. Esse formulário terá seus dados enviados para o back-end onde alguma linguagem de programação vai recebê-los e processá-los. Essa parte está fora do escopo deste material.
Mais uma vez, o processo que usamos aqui está acontecendo no front-end, o ambiente mais obscuro que um desenvolvedor pode encontrar porque não temos nenhum controle sobre ele, sobre quem está operando nosso site, seu nível de conhecimento e sua ânsia pelo lado sombrio, portanto, mesmo usando algum recurso de validação no front-end, SEMPRE valide os dados no back-end novamente, usando os melhores recursos possíveis, disponíveis na linguagem desse lado.
Finalmente, não confunda validade com veracidade. Por exemplo, o formulário acima consegue validar se o formato do e-mail inserido é válido, mas não consegue confirmar se é um e-mail legítimo, que realmente existe. Para isso, precisamos de processos bem mais complicados...
Conclusão
Se antes, precisavamos de códigos JavaScript complexos para validar e enviar formulários de forma um pouco menos insegura, hoje, o próprio HTML5 já faz boa parte do processo e, se der tudo certo, as novas versões da linguagem vão melhorar ainda mais esses recursos.
Não deixe de comentar se tiver dúvidas ou colaborações.