CSS :invalid Pseudo Classe
Scopri come CSS :invalid stila i campi modulo che non superano i vincoli di validazione, con esempi, avvertenze, consigli sull'accessibilità e supporto browser.
La pseudo-classe CSS :invalid corrisponde ai controlli associati ai moduli — come <input>, <select> e <textarea> — il cui valore corrente non supera i vincoli di validazione integrati nel browser. È la parte visiva dell'API di validazione dei vincoli di HTML: il browser valuta la validità e :invalid ti consente di stilizzare il risultato con puro CSS, senza JavaScript.
Questa pagina copre esattamente quando :invalid corrisponde, come stilizzarlo senza allertare gli utenti prima che abbiano digitato qualcosa, la particolarità dei pulsanti radio, l'alternativa moderna :user-invalid e come mantenere il feedback degli errori accessibile.
Quando un elemento corrisponde a :invalid?
Un controllo corrisponde a :invalid quando porta almeno un vincolo di validazione e il suo valore corrente viola quel vincolo. Trigger comuni:
| Vincolo | Attributo / tipo | Fallisce quando… |
|---|---|---|
| Obbligatorio ma vuoto | required | il campo non ha valore |
| Formato email errato | type="email" | il valore non è un'e-mail sintatticamente valida |
| Formato URL errato | type="url" | il valore non è un URL assoluto valido |
| Fuori dall'intervallo | min / max su type="number", type="date", ecc. | il valore è al di fuori dell'intervallo consentito |
| Step errato | step | il valore non si allinea con l'intervallo dello step |
| Mancata corrispondenza del pattern | pattern | il valore non corrisponde alla regex |
| Troppo lungo / troppo corto | minlength / maxlength | la lunghezza del valore è al di fuori dell'intervallo consentito |
Se un controllo non ha vincoli (un semplice <input type="text"> senza attributi aggiuntivi), viene considerato senza vincoli e né :valid né :invalid si applicano ad esso.
Un elemento <fieldset> corrisponde a :invalid quando uno qualsiasi dei suoi controlli modulo discendenti non è valido.
Per il lato opposto, vedi la pseudo-classe :valid, che corrisponde ai controlli che superano tutti i vincoli. La pseudo-classe :required corrisponde ai campi obbligatori indipendentemente dal fatto che abbiano un valore.
Sintassi
:invalid {
/* declarations applied to all invalid form controls */
}Limita :invalid a un tipo di elemento specifico per mantenere gli stili prevedibili:
input:invalid,
textarea:invalid {
border: 2px solid #c00;
outline: none;
}Esempio di base
Il campo email qui sotto è pre-compilato con un indirizzo non valido ("not-an-email"), quindi corrisponde a input:invalid al caricamento e ottiene un bordo rosso.
<!DOCTYPE html>
<html>
<head>
<title>:invalid example</title>
<style>
input:invalid {
border: 2px solid #c00;
background-color: #fff0f0;
}
input:valid {
border: 2px solid #090;
background-color: #f0fff0;
}
</style>
</head>
<body>
<h2>:invalid selector example</h2>
<form>
<label for="email">Email:</label>
<input id="email" type="email" value="not-an-email" required />
</form>
</body>
</html>Evitare il "rosso prematuro"
Il problema più comune con :invalid: un campo required vuoto è già non valido nel momento in cui la pagina si carica, quindi un modulo appena aperto può diventare rosso prima che l'utente abbia digitato qualcosa. Questo risulta accusatorio.
Opzione 1 — stilizza solo quando il campo è attivo
Mostra il bordo di errore solo mentre l'utente è attivamente nel campo:
input:invalid:focus {
border-color: #c00;
outline: 2px solid #c00;
outline-offset: 1px;
}Questo è semplice ma scompare nel momento in cui l'utente passa al campo successivo con Tab, quindi un campo obbligatorio vuoto sembra di nuovo a posto.
Opzione 2 — nascondi l'errore mentre il placeholder è visibile
:placeholder-shown è vero quando il testo placeholder è visualizzato (cioè il campo è vuoto). Combinandolo con :not, lo stile di :invalid si attiva solo quando l'utente ha digitato qualcosa:
/* Only show the error style when the field has a value that is invalid */
input:invalid:not(:placeholder-shown) {
border-color: #c00;
}Questo è efficace ma richiede che ogni campo abbia un attributo placeholder impostato — altrimenti :placeholder-shown non è mai vero e la guardia non fa nulla.
Opzione 3 — usa :user-invalid (standard moderno)
La pseudo-classe :user-invalid è stata progettata specificamente per risolvere questo problema. Si comporta come :invalid ma corrisponde solo dopo che l'utente ha interagito con il controllo (digitato, deselezionato o inviato il modulo):
/* Supported in all modern browsers as of 2024 */
input:user-invalid {
border-color: #c00;
}
/* Fallback for older browsers */
@supports not selector(:user-invalid) {
input:invalid:not(:placeholder-shown) {
border-color: #c00;
}
}:user-invalid è la soluzione più pulita quando puoi farci affidamento. Firefox la supporta da anni come :-moz-ui-invalid; lo standard :user-invalid è ora disponibile in tutti i browser moderni.
Approccio allo stile
Un bordo pieno severo di 2 px rosso è leggibile ma stridente. Considera di combinare un cambiamento del bordo con un sottile box-shadow per un aspetto più morbido:
input:invalid:not(:placeholder-shown) {
border-color: #c00;
box-shadow: 0 0 0 3px rgba(204, 0, 0, 0.15);
}Evita di affidarti solo al colore — vedi la sezione Accessibilità di seguito.
Avvertenze
Pulsanti radio
Quando un gruppo di pulsanti radio ha required su uno degli input, ogni pulsante del gruppo corrisponde a :invalid mentre nessuno è selezionato. Stilizzare piccoli cerchi radio non è pratico; invece, stilizza il <fieldset> circostante o il <label>:
/* Style the fieldset, not the radio buttons themselves */
fieldset:invalid {
border: 2px solid #c00;
border-radius: 4px;
padding: 8px 12px;
}Tutti i pulsanti radio in un gruppo condividono lo stesso attributo name — è questo che li rende un gruppo nel modello di validità del browser.
Campi opzionali vuoti
Un semplice <input type="text"> senza required, senza pattern e senza vincoli di lunghezza è sempre :valid anche quando è vuoto. :invalid si attiva solo quando esiste un vincolo ed è violato.
select e textarea
<select> corrisponde a :invalid se è required e il suo value corrente è una stringa vuota (un pattern comune è un'opzione segnaposto "-- scegli --" <option value=""> in cima). <textarea> segue le stesse regole di <input> per required, minlength e maxlength.
Firefox e :-moz-ui-invalid
Firefox ha a lungo applicato stili tramite :-moz-ui-invalid, che si attiva solo dopo l'interazione dell'utente — in pratica il comportamento di :user-invalid integrato. Se aggiungi le tue regole :invalid e le testi in Firefox, il campo potrebbe sembrare a posto (perché la guardia predefinita per l'interazione dell'utente del browser è attiva), poi comportarsi diversamente in Chrome (dove la guardia predefinita è disattivata). Definisci regole esplicite e usa :user-invalid con un fallback per ottenere un comportamento coerente.
Accessibilità
Il colore da solo non è mai sufficiente per comunicare un errore — gli utenti con deficit nella percezione dei colori potrebbero non percepire un bordo rosso. Abbina lo stile di :invalid con:
- Un messaggio di testo visibile che spieghi cosa è andato storto e come correggerlo.
- Un'icona o un simbolo accanto al cambiamento di colore (ad es., una ✕ o un'icona di avviso).
aria-invalid="true"sul controllo in modo che i lettori di schermo lo annuncino come non valido.aria-describedbyche punta all'elemento del messaggio di errore in modo che la descrizione venga letta automaticamente.
<label for="email">Email address</label>
<input
id="email"
type="email"
aria-invalid="true"
aria-describedby="email-error"
required
/>
<span id="email-error" role="alert">
Please enter a valid email address.
</span>Il role="alert" sullo span dell'errore fa sì che i lettori di schermo annuncino il messaggio non appena appare nel DOM, anche senza focus.
Pseudo-classi correlate
| Pseudo-classe | Corrisponde quando… |
|---|---|
:valid | il controllo supera tutti i suoi vincoli |
:required | il controllo ha l'attributo required |
:optional | il controllo non ha required |
:out-of-range | il valore di un input numerico/data supera min/max |
:in-range | il valore di un input numerico/data è compreso tra min/max |
:placeholder | il testo placeholder di un input |
:focus | il controllo ha attualmente il focus da tastiera |
Supporto browser
:invalid fa parte di Selectors Level 4 ed è supportato in tutti i principali browser da molti anni. :user-invalid (la variante consapevole dell'interazione) è disponibile a partire da Chrome 119, Firefox 88 (come :-moz-ui-invalid molto prima), e Safari 16.5.
Per ulteriori informazioni sugli attributi di vincolo nativi di HTML, vedi <input> e HTML Forms.