Questa è la traduzione dell'articolo Forward Thinking Form Validation di Ryan Seddon, pubblicato originariamente su A List Apart il 21 Settembre 2010. La traduzione viene qui presentata con il consenso dell'editore (A List Apart Magazine) e dell'autore.
La validazione dei form è sempre stata una questione problematica, sin dagli albori del web. All'inizio ci fu il messaggio di errore riassuntivo della validazione lato server. Poi siamo passati alla validazione lato client per verificare la correttezza della compilazione mentre l'utente riempie i vari campi. Ora siamo di fronte alla marcia trionfale di HTML5 e CSS3: il capitolo dedicato ai form della specifica HTML5 presenta nuovi tipi di input e di attributi che rendono possibile l'inserimento di specifici vincoli nella compilazione e nella conseguente validazione del modulo. Il modulo Basic UI dei CSS3 fornisce diverse pseudo-classi per aiutarci ad applicare degli stili ai diversi stati della validazione e a cambiare l'aspetto dei campi in base alle azioni degli utenti. Vediamo come combinare queste due tecnologie per creare un validatore di form basato sui CSS che abbia un ampio supporto sui browser attuali.
Più aiutiamo in tempo reale un utente a procedere nella compilazione di un form, meno probabile sarà l'eventualità che egli compia degli errori. Date un'occhiata all'esempio di validazione dei form con i CSS allegato a questo articolo in un browser che supporta le pseudo-classi Basic UI dei CSS3 (Chrome 4+, Safari 5+, Opera 9.6+). Ho usato queste pseudo-classi e gli attributi dei form di HTML5 per creare il tutto. Vediamo come funziona.
Pseudo-classi CSS3 per l'interfaccia utente
Il modulo UI presenta diverse pseudo-classi che aiutando ad applicare stili ai campi di un form in diversi stati:
valid
invalid
required
optional
in-range
out-of-range
read-only
read-write
Nella demo ho usato le pseudo-classi required
, invalid
e valid
per implementare la validazione CSS:
input:focus:required:invalid {
background: pink url(ico_validation.png) 379px 3px no-repeat;
}
input:required:valid {
background-color: #fff;
background-position: 379px -61px;
}
Dal momento che vogliamo solo specificare che un certo campo non è valido quando esso riceve il focus, usiamo la pseudo-classe focus
per attivare lo stile che denota un campo non valido (ovviamente, segnalare come non validi tutti i campi obbligatori sin dall'inizio sarebbe una scelta di design poco azzeccata).
Spostando il focus su un campo obbligatorio che non sia valido attiviamo lo stile che visualizza il punto esclamativo, cosa che avvisa l'utente sul fatto che qualcosa deve essere inserito nel campo. Una volta che i vincoli di validazione siano stati soddisfatti, si attiva la pseudo-classe valid
. Ora, rimuoviamo la pseudo-classe focus
così che rimanga solo il segnale verde che indica un campo corretto.
Tutte le pseudo-classi elencate sopra si spiegano da sé. Le pseudo-classi in-range
e out-of-range
dovrebbero usate insieme con gli attributi min
e max
, su un input basato su un intervallo, su un campo per l'immissione di numeri o su tutti quei tipi di input che accettano quegli attributi. Per esempio, se un utente inserisce un valore che è fuori dall'intervallo (out-of-range
, possiamo usare la pseudo-classe per cambiare lo stile che riflette lo stato; possiamo fare lo stesso per in-range
.
Solo Opera supporta al momento le pseudo-classi relative al range. Altri browser lo faranno presto.
Nuovi di tipi di input e attributi
La specifica sui form di HTML5 introduce anche nuovi tipi di input come email
, url
e number
. Per esempio, email
attiva la pseudo-classe valid
solo quando l'utente inserisce un indirizzo e-mail valido; la stessa cosa si applica al campo di tipo number
o url
. I vincoli per la validazione di un campo url
variano da browser a browser. In Opera, inserendo qualcosa come http://
il contenuto del campo è considerato valido. Su Chrome scrivere http://w
è valido. Su Safari è valido scrivere semplicemente http:
.
Ci sono pure alcuni attributi che facilitano la validazione come placeholder
, required
, maxlength
, pattern
, min
, max
e step
:
<input id="postcode" name="postcode" type="number" min="1001" max="8000"
maxlength="4" required />
Il campo postcode
usa un input di tipo number
e alcuni attributi. In Australia un codice postale può essere solo di 4 cifre, così impostiamo un attributo maxlenght
pari a 4
per restringere l'inserimento di ulteriori caratteri. Vogliamo anche limitare quanto alto o quanto basso potrà essere il valore di un codice, così usiamo min
e max
per definire i limiti. L'attributo required
(obbligatorio) si spiega da sé.
Possiamo usare l'attributo step
per restringere ulteriormente un campo sui cui si siano usati min
e max
. Di default, step
è impostato su 1
, così ogni numero compreso tra min
e max
incrementato almeno di 1 è valido. Cambiando il valore di step
a 100
, rende valido il campo se l'utente inserisce un valore incrementato di 100. Per esempio, se imposto l'attributo step
su 100
, 1001 sarà valido, così cpme 1101, 1201, 1301, etc.
Trovare il pattern
Per attivare la pseudo-classe invalid
in condizioni più specifiche, come su un rudimentale numero di telefono, possiamo usare l'attributo pattern
, che ci consente di applicare ad un campo un'espressione regolare:
<input type="tel" id="tel" name="tel" pattern="d{10}" placeholder=
"Please enter a ten digit phone number" required />
L'espressione regolare appena vista è semplice. Dice: "Accetto solo dieci caratteri e non di più". Così, il campo sarà sempre non valido fino a quando non vengano soddisfatti i requisiti dell'espressione regolare. Notate come si sia usato l'attributo placeholder
per dare all'utente un aiuto nella compilazione.
Possiamo spingere molto in avanti la potenza dell'attributo pattern
applicando un'espressione regolare più complessa, come su questo campo per le password:
<input id="password" name="password" type="password" title="Minimum 8
characters, one number, one uppercase and one lowercase letter" required
pattern="(?=^.{8,}$)((?=.*d)|(?=.*W+))(?![.n])(?=.*[A-Z])
(?=.*[a-z]).*" />
Dal momento che abbiamo specifiche condizioni che restringono quanto può essere inserito dagli utenti, costringendoli a creare password più sicure, definiamo un'espressione regolare come mostrato sopra. La password deve essere almeno di 8 caratteri, contenere un numero, una lettera in minuscolo e una in maiuscolo.
Per aiutare un utente a soddisfare queste condizioni, usiamo l'attributo title
per aiutarlo a comprendere esattamente quali siano i requisiti. Non usiamo in questo caso l'attributo placeholder
, perché c'è bisogno di una spiegazione più lunga e placeholder
dovrebbe essere usato solo per brevi suggerimenti.
Aggiungere un aiuto
Se l'utente non passa mai con il mouse sul campo, e si sposta invece con il tasto tabulatore, non visualizzerà mai le istruzioni di aiuto comprese nell'attributo title
. Potete notare che sui campi per il telefono, per il codice postale e per le password, appare un testo di aiuto quando il campo ha bisogno di ulteriori spiegazioni in vista della compilazione.
<input id="password" type="password" />
<p class="validation01">
<span class="invalid">Minimum 8 characters, one number, one uppercase
letter and one lowercase letter</span>
<span class="valid">Your password meets our requirements, thank you.
</span>
</p>
Il markup visto qui sopra introduce un contenitore extra con i box d'aiuto per quando il campo è valido e per quando è non valido. In questo modo, quando il campo non è valido, conterrà l'informazione extra per andare in aiuto dell'utente. Quando tutto è corretto, il nostro messaggio e il segno verde lo rassicurano sul fatto che la compilazione è avvenuta correttamente.
.validation01 {
background: red;
color: #fff;
display: none;
font-size: 12px;
padding: 3px;
position: absolute;
right: -110px;
text-align: center;
top: 0;
width: 100px;
}
input:focus + .validation01 {
display: block;
}
input:focus:required:valid + .validation01 {
background: green;
}
input:focus:required:valid + .validation01 .invalid {
display: none;
}
input:focus:required:invalid + .validation01 .valid {
display: none;
}
Per mostrare o nascondere il box di aiuto, a seconda dello stato del campo, possiamo prendere il campo come target facendo ricorso alle pseudo-classi, usando il selettore dell'elemento adiacente (+
). Una volta che il campo sia stato compilato correttamente, lo sfondo cambia diventando verde e viene visualizzato un messaggio di validità.
Fine prima parte.
Problemi di usabilità con l'approccio corrente
C'è principalmente un problema rispetto al modo in cui funziona la pseudo-classe invalid
quando un campo è settato come obbligatorio (required
) e ha condizioni addizionali che devono essere soddisfatte. Per esempio quando un campo è definito come required
e il suo tipo è impostato su email
. Dal momento che il campo è sempre non valido fino a quando tutte le condizioni non vengono soddisfatte, esso attiverà gli stili che si applicano quando un campo non è valido. In questo caso, nella nostra demo iniziale, il campo sarà da subito non valido e marcato di rosso con un messaggio di errore anche prima che l'utente abbia inserito qualcosa. Ecco perché usiamo la pseudo-classe focus
per visualizzare gli stili di non validità solo quando un campo ha il focus. Ciò non è ottimale: se un utente si sposta dal campo senza soddisfare le condizioni di validazione, il campo non indicherà che qualcosa è sbagliato fino a quando il focus non torna su di esso.
Una soluzione per questo problema potrebbe consistere nell'aggiungere la pseudo-classe indeterminate
disponibile per i radio button e per i checkbox. Tecnicamente, un campo che ha più condizioni rispetto all'unica rappresentata dell'essere obbligatorio, quando è vuoto non è valido né non valido, è piuttosto indeterminato. Questa idea correggerebbe il problema del messaggio di validità che compare anche quando il campo è vuoto e ci consente di applicare uno stile a seconda della condizione di validità.
Inoltre, possiamo aggiungere delle funzionalità interessanti senza ricorrere a Javascript. Possiamo indicare in quale stato si trova un campo, se è obbligatorio, possiamo dire ad esso di conformarsi ad un certo pattern con con un'espressione regolare, specificare valori minimi e massimi e molto altro. Ma cosa accade se non è abbastanza? Cosa possiamo fare se volessimo portare il tutto più avanti? Beh, siamo fortunati, perché la specifica HTML5 a proposito dei form definisce anche una API per i vincoli di validazione.
API per i vincoli di validazione
Insieme ai nuovi attributi, ai nuovi tipi di input e alle pseudo-classi CSS3, abbiamo a disposizione nella specifica HTML5 una semplice API Javascript che ci consente di estendere le funzionalità di validazione con comodi metodi, attributi ed eventi. Date un'occhiata alla demo aggiornata che usa tra l'altro proprio questa API.
Ogni campo del modulo ha un attributo chiamato validity
. L'attributo validity
restituisce un oggetto ValidityState
che rappresenta lo stato di validazione corrente di un elemento. L'oggetto ValidityState
contiene diversi attributi boolaani che identificano in quale condizione di validità si trova l'elemento corrente. In pratica, si tratta di una serie risposte di tipo vero/falso (true/false) che dicono ad uno sviluppatore cosa esattamente c'è di sbagliato in un campo:
- valueMissing: Questo attributo restituisce
true
se un campo obbligatorio è vuoto. - typeMismatch: Questo valore si applica a tutti i nuovi tipi di attributo. Per esempio, se un valore per un campo
email
non è corretto, questo attributo restituiscetrue
. - patternMismatch: Quando un elemento contiene l'attributo
pattern
e non è conforme alle condizioni impostate nell'espressione regolare, questo attributo restituiscetrue
. - tooLong: Quando un elemento supera la sua proprietà
maxlenght
questo attributo restituiscetrue
. - rangeUnderflow e rangeOverflow: Se gli attributi
min
emax
di un elemento sono sopra o sotto i valori specificati, questo attributo restituiscetrue
. - stepMismatch: Quando un elemento con l'attributo
step
non è conforme al valore richiesto perstep
, questo attributo restituiscetrue
. - valid: Se uno dei valori appena elencati restituisce
true
, questo attributo restituiscefalse
per indicare che un form non è valido. Altrimenti, se tutte le condizioni sono soddisfatte, restituiràtrue
.
Dettagli aggiuntivi
L'evento invalid
è un'altra funzionalità molto comoda. Sarà invocata dal campo quando esso è ancora non valido. Così possiamo attaccare ad esso una qualche forma di interazione e, nel nostro caso, modificare lo stile del campo affinché rifletta il suo stato.
Inoltre, il metodo checkValidity
può essere eseguito su un campo individuale o su un form nel suo complesso, e può restituire true
o false
. Eseguire il metodo fa anche anche programmaticamente attivare l'evento invalid
su tutti i campi non validi, oppure, se viene eseguito su un campo singolo, solo su quello.
Rivediamo la demo
Riprendiamo la nostra demo e miglioriamola con l'uso della API sulla validazione. Basandoci su quello che abbiamo appreso da Luke Wroblewski nel suo articolo La validazione inline dei form e sulle nostre esperienze, possiamo applicare queste idee al nostro modulo per creare un'esperienza di validazione ottimale.
La prima cosa che possiamo correggere è l'applicazione immediata dello stile di errore su un campo non valido. Piuttosto che applicare subito uno stile per indicare che l'utente non ha compilato il campo in modo corretto, aspettiamo fino a quando non si sposta dal campo per mostrare qualunque tipo di messaggio.
Se l'utente soddisfa i requisiti di compilazione mentre il focus è ancora su un certo campo, gli facciamo subito sapere che il campo è corretto e valido. Lo facciamo collegando l'evento input
per verificare se se il campo è valido. Quando lo è, aggiorniamo lo stile perché il campo rifletta i cambiamenti.
Se il campo contiene valori non corretti e l'utente si sposta sul prossimo campo, l'evento blur
verificherà la validità del campo e quindi applicherà gli stili di errore per far sapere all'utente che ha sbagliato qualcosa. Manterrà lo stile di errore fino a quando i requisiti non siano soddisfatti.
Cosa fare con i vecchi browser?
Tutti gli argomenti discussi sono piuttosto nuovi e il supporto sui vari browser, sebbene sia buono, non ci garantirebbe nel contesto di un ambiente di produzione rivolto al mondo reale, quello in cui dovremmo supportare tutti i browser. Ecco a cosa serve lo script che ho creato.
Per i browser che non supportano i form HTML5 e la API per la validazione, lo script emula quelle funzionalità. Per i browser che supportano queste funzionalità, lo script identifica il supporto e si affida alle funzionalità native. Diamo ora un'occhiata alla demo ulteriormente aggiornata con l'aggiunta del nuovo script. Provatelo con Firefox e IE per verificare che funziona esattamente come sui browser che supportano le funzionalità di validazione nativamente.
Supporto dei browser
Lo script è stato testato e funziona sui seguenti browser:
- IE6+
- Firefox 1+—FF4 avrà un supporto nativo.
- Chrome 4+—Supporto nativo.
- Safari 3.2+—Safari 5 ha un supporto nativo.
- Opera 9.6+—Supporto nativo.
Le seguenti funzionalità sono emulate nello script:
- ogni campo ha l'oggetto
validity
in modalità live e vi fornirà informazioni sullo stato corrente del campo; - il metodo
checkValidity
è disponibile e indica se il form o uno specifico elemento non sono validi; - sono supportati gli attributi
pattern
,placeholder
,required
,min
,max
estep
; - per le textarea sono supportati gli attributi
placeholder
erequired
; - l'attributo
required
è supportato anche per i campi di tipo select; - i tipi di input
email
eurl
sono verificati rispetto ad una espressione regolare integrata nel codice e saranno non validi fino a quando non siano conformi a tale espressione regolare.
Validazione in abbondanza!
Il supporto dei browser per i form HTML5 e per il modulo UI dei CSS3 sta iniziando ad essere più ampio. Opera 9 ha guidato la pattuglia implementando i Web Forms 2.0 prima che essi fossero incorporati nella specifica HTML5, ma ha un supporto per il modulo UI dei CSS3 solo a partire dalla versione 9.6. Chrome garantisce il supporto dalla versione 4, Safari ha implementato tutto di recente con la versione 5, Firefox introdurrà un supporto esteso con la versione 4.0, IE9, se continua sulla via intrepresa del progresso nel supporto degli standard, dovrebbe avere un supporto di base per queste funzionalità nelle prossime release.
Possiamo fare cose straordinarie con questi nuovi moduli di HTML5 e CSS3. Man mano che i browser allargheranno il supporto queste tecniche diventeranno un'alternativa effettiva che potrà adattarsi ai problemi semplici e complessi della validazione dei form.