Estilizar formulários HTML sempre foi notoriamente difícil (e chato) de se fazer com CSS, mas existem vários seletores pouco usados que ajudam de maneira significativa para estilizar formulários com CSS puro.
:placeholder-shown
:placeholder-shown
é relativamente novo e permite detectar se um placeholder está atualmente visível para o usuário. Isso pode ser útil em situações como ocultar e mostrar dinamicamente o label associado ao input.
Neste exemplo, o label é ocultado até que o usuário comece a digitar alguma coisa, ocultando assim o placeholder.
1 2 3 4 |
<div class="form-group"> <input type="text" id="dynamic-label-input" placeholder="Enter some text"> <label for="dynamic-label-input">Enter some text</label> </div> |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
.form-group { padding-top: 1.5rem; position: relative; } label { opacity: 1; position: absolute; top: 0; transform: translateY(0); transition: all 0.2s ease-out; } input:placeholder-shown + label { opacity: 0; transform: translateY(1rem); } |
Observe que, para que este técnica funcione, o label deve vir depois do input. Mas também seria possível inverter a ordem com o input e fazer a estilização com :has()
da seguinte forma:
1 2 3 4 |
:has(input:placeholder-shown) label { opacity: 0; transform: translateY(1rem); } |
Se ainda não conhece o seletor :has()
, confira nosso vídeo:
:required
O seletor :required
para indicar que um input possui o atributo required
(obrigatório).
Comumente, isso seria feito com JavaScript, mas este exemplo demonstra uma abordagem de estilização de formulário com CSS puro.
1 2 3 |
<label for="required-input">Required input</label> <input type="text" id="required-input" required> <span class="help-text"></span> |
1 2 3 |
input:required + .help-text::before { content: '* Required'; } |
:optional
O seletor :optional
faz o oposto de :required
, servindo para estilizar inputs de formulário que não sejam obrigatórios.
Imaginando uma estrutura HTML semelhante à do exemplo anterior, o CSS ficaria:
1 2 3 |
input:optional + .help-text::before { content: '* Optional'; } |
:disabled
Como a maioria deve saber, :disabled
é essencial para mostrar se um input está desabilitado ou não.
Ele é familiar para a maioria dos devs, mas, ainda assim, é importante ser citado em um artigo sobre estilização de formulários com CSS puro.
1 2 3 4 5 |
input:disabled { background-color: var(--gray-lightest); border-color: var(--gray-lighter); color: var(--gray-light); } |
:read-only
Um input com o atributo readonly
deve transmitir um significado ligeiramente diferente (portanto, uma estilização diferente) de um input desabilitado. Felizmente, existe o seletor :read-only
para ajudar com isso.
1 |
<input type="text" value="Read-only value" readonly> |
1 2 3 4 5 |
input:read-only { border-color: var(--gray-lighter); color: var(--gray); cursor: not-allowed; } |
:valid
Embora grande parte da validação de formulários seja feita com JavaScript, é possível aproveitar as vantagens da validação de formulário nativas de HTML e estilizar com CSS puro.
O seletor :valid
oferece a oportunidade de se estilizar qualquer input que passou pelas regras de validação nativas do navegador.
Por exemplo, é possível usar background-image
para exibir uma imagem de check, indicando que um campo passou pela validação.
1 2 3 4 5 |
input:valid { background-image: url('data:image/svg+xml,...'); border-color: var(--color-primary); } |
:invalid
Este seletor :invalid
verifica se uma entrada não está passando pelas regras de validação nativas do navegador (por exemplo, se uma entrada de e-mail não contém um e-mail real).
É possível exibir uma imagem, como no exemplo anterior:
1 2 3 4 5 |
input:invalid { background-image: url('data:image/svg+xml,...'); border-color: var(--color-error); } |
Ou personalizar algumas mensagens de validação para cada tipo de input usando marcação auxiliar e pseudo-elementos.
1 2 3 |
<label for="invalid-email">Invalid input</label> <input type="email" id="invalid-email" value="notanemail"> <span class="help-text"></span> |
1 2 3 |
input[type='email']:invalid + .help-text::before { content: 'You must enter a valid email.' } |
:in-range/:out-of-range
Os seletores :in-range
e :out-of-range
detectam se o valor de um input numérico está dentro dos valores min
e max
especificados ou não.
1 2 3 4 5 6 7 8 9 |
<label for="out-of-range-input">Out-of-range input</label> <input type="number" id="out-of-range-input" min="1" max="10" value="12" > <span class="help-text">(value must be between 1 and 10)</span> |
1 2 3 |
input:out-of-range + .help-text::before { content: 'Out of range'; } |
:checked
A maioria dos devs está familiarizada com o seletor :checked
, que permite aplicar estilos personalizados a checkboxes e radios quando marcados.
Ele torna possível realizar estilização de formulários com CSS puro de muitas maneiras: com elementos auxiliares, usando seletores avançados, :has()
etc.
1 2 3 4 |
<div class="checkbox"> <input type="checkbox"/> <label>Option</label> </div> |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
&:checked + label::before { background-color: var(--color-primary); } &:checked + label::after { border: solid white; border-width: 0 2px 2px 0; content: ''; display: block; height: 0.5rem; left: 0.375rem; position: absolute; top: 0.2rem; transform: rotate(45deg); width: 0.25rem; } |
Aproveite recursos nativos para estilizar formulários com CSS puro
A estilização de formulários com CSS puro é conhecida e aproveitada por muitos devs. Aliás, é altamente indicado que você também faça uso desses recursos.
Afinal, o próprio HTML e CSS evoluíram (e evoluem) para fornecerem recursos para que interações e estilizações nativos possam ser usados da melhor maneira possível.