No. 103

Titolo originale: Forward Thinking Form Validation

Pubblicato in: Browser, CSS, HTML, Javascript

Scritto da Ryan Seddon

La validazione delle form è stata una questione puntigliosa fin dalla nascita del web. Prima di tutto ci fu il riassunto degli errori della validazione server-side. Poi ci si è evoluti fino alla validazione client-side per verificare i risultati inline. Ora, abbiamo quel gigante in marcia che è HTML5 e CSS3: il capitolo sulle form di HTML5 offre nuovi tipi di input ed attributi che rendono possibili dei vincoli di validazione. Il basic UI module di CSS3 fornisce diverse pseudo-classi che ci aiutano ad assegnare uno stile a quegli stati di validazione e a cambiare l'aspetto di un campo a seconda delle azioni dell'utente. Diamo un'occhiata a come combinare le due cose per creare un form validator basato su CSS che sia abbastanza ampiamente supportato dai browser.

Più riusciamo a guidare un utente su come deve completare un campo di una form in tempo reale, minori saranno le possibilità che questi facciano degli errori. Guardate l'esempio di CSS3 form validation in un browser che supporti le pseudo-classi UI di CSS3 come Chrome 4+, Safari 5+ o Opera 9.6+. Utilizzo le pseudo-classi UI di CSS3 e gli attributi delle form HTML5 per fare una validazione basata su CSS. Vediamo come funziona.

Le pseudo-classi UI di CSS3

Il modulo UI ha molte pseudo-classi che aiutano ad assegnare degli stili ai campi delle form nei vari stati.

  • valid
  • invalid
  • required
  • optional
  • in-range
  • out-of-range
  • read-only
  • read-write

Nella demo di cui sopra, ho usato le pseudo-classi required, invalid e valid per ottenere 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 denotare che un campo non è valido una volta che ha il focus, usiamo la pseudo-classe focus per azionare lo stile assegnato alla non validità. (Naturalmente, contrassegnando tutti i campi obbligatori come non validi fin dall'inizio sarebbe una scelta progettuale piuttosto scarsa).

Portare il focus su un campo non valido obbligatorio fa scattare lo stile che mostra un'icona di pericolo [un triangolo rosso con un punto esclamativo all'interno, ndt], che avvisa l'utente che qualcosa deve essere inserito. Una volta che i vincoli di validazione del campo sono soddisfatti, si attiva la pseudo-classe valid. Ora, togliamo la pseudo-classe focus in modo che rimanga il segno di spunta di colore verde che indica che il campo è corretto.

Tutte le pseudo-classi elencate sopra si spiegano da sole. Le pseudo-classi in-range e out-of-range devono essere usate insieme agli attributi min e max, sia che siano su un input di tipo range, un campo number o su qualunque altro tipo che accetta questi attributi. Ad esempio, se un utente inserisce un valore che è out-of-range, possiamo usare la pseudo-classe per cambiare lo stile per riflettere lo stato; allo stesso modo possiamo fare lo stesso con i valori in-range.

Al momento, solo Opera supporta le pseudo-classi di range. Gli altri browser lo faranno presto.

Ulteriori tipi ed attributi che ci aiutano

Le form HTML5 introducono inoltre nuovi tipi di input come email, url e number. Ad esempio, email fa scattare solo la pseudo-classe valid quando l'utente inserisce un indirizzo e-mail valido: lo stesso vale per number e url. I vincoli sulla validazione dell'url differiscono tra i vari browser. In Opera, scrivere “http://” contrassegna il campo url come valido. In Chrome scrivere “http://” lo contrassegna come valido, mentre scrivere semplicemente “http:” in Safari contrassegna un url come valido.

Ci sono anche alcuni attributi che aiutano 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 codice postale usa il nuovo tipo number e qualche altro nuovo attributo. In Australia, un codice postale può solo avere quattro cifre, così impostiamo l'attributo maxlength per restringerlo. Vogliamo anche restringere i limiti inferiore e superiore del codice postale, così usiamo gli attributi min e max per stabilire dei limiti. L'attributo required si spiega da solo.

Possiamo usare l'attributo step per restringere ulteriormente un campo con min e max. Di default, step è impostato a uno, così che qualsiasi numero tra i valori minimo e massimo incrementato di almeno uno sia validato. Cambiare step a 100 valida tra il range impostato se il valore che l'utente ha inserito è un incremento di 100. Ad esempio, se impostiamo l'attributo step a 100 sul campo codice postale, 1001 sarà un valore valido, così come 1101, 1201, 1301, etc.

Trovare il pattern

Per azionare la pseudo-classe invalid su condizioni più specifiche, così come un rudimentale numero di telefono, possiamo usare l'attributo pattern che ci permette di applicare un'espressione regolare al campo.


<input type="tel" id="tel" name="tel" pattern="\d{10}" placeholder=
"Please enter a ten digit phone number" required />

L'espressione regolare di cui sopra è semplice. Dice “Accetterò solo esattamente dieci cifre e niente altro.” In questo modo, il campo sarà sempre non valido finché non saranno soddisfatti i requisiti dell'espressione regolare. Notate l'uso dell'attributo come placeholder per dare all'utente un piccolo suggerimento.

Possiamo veramente spingere il potere dell'attributo pattern applicando un'espressione regolare più complessa come faccio nel campo 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 delle condizioni specifiche che restringono l'insieme di valori che gli utenti possono inserire, forzandoli a creare una password più sicura, impostiamo un'espressione regolare complessa come mostrato sopra. La password deve essere lunga almeno otto caratteri, contenere un numero, una lettera minuscola e una lettera maiuscola.

Per aiutare un utente a soddisfare queste condizioni, usiamo l'attributo title per aiutarli a comprendere esattamente quali siano le richieste. Non usiamo l'attributo placeholder in questo caso, perché necessita di maggiori spiegazioni e placeholder dovrebbe essere solo usato per brevi indicazioni.

Aggiungere suggerimenti preziosi

Se l'utente non passa mai sul campo e invece scorre fra questi con il tab, potrebbe non notare mai le istruzioni extra nell'attributo title. Potete notarlo sui campi phone, postcode e password: un prezioso aiuto appare quando il campo ha bisogno di istruzioni extra.


<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 di cui sopra ha un container extra che ha sia il box di suggerimento invalid sia quello valid. In questo modo, quando il campo non è valido, conterrà delle informazioni extra per aiutare l'utente. Quando invece compilano il campo correttamente, il nostro messaggio e la spunta verde lo rassicurano di averlo compilato 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 suggerimento d'aiuto, a seconda dello stato in cui si trova il campo, possiamo puntare al campo concatenando le pseudo-classi, usando i sibling combinator per concentrarci sul suggerimento corretto. Una volta che il campo sarà stato compilato correttamente, il background diventa verde ed il messaggio di validità viene mostrato.

Considerazioni di UX sull'approccio corrente

C'è un problema importante riguardo il modo in cui la pseudo-classe invalid funziona attualmente quando un campo è richiesto e ha delle condizioni aggiuntive che devono essere soddisfatte, ad esempio, quando un campo è required e il suo tipo è email. Poiché il campo è sempre non valido finché le condizioni non sono soddisfatte, avrà gli stili del campo non valido. In questo caso, il campo sarà istantaneamente non valido e marcato con il rosso, con errori ancora prima che l'utente abbia inserito qualunque cosa. E' per questo che usiamo la pseudo-classe focus per mostrare gli stili del campo non valido solo quando un campo ha il focus. Questo non è ottimale: se un utente si sposta dal campo senza aver soddisfatto le condizioni di validazione, il campo non indicherà che qualcosa è sbagliato finché l'utente non riporta di nuovo il focus a questo.

Una soluzione proposta per questo sarà quella di aggiungere la pseudo-classe indeterminate disponibile sugli input radio e checkbox. Tecnicamente, un campo che ha più condizioni di quelle richieste quando è vuoto non è né valido né non valido, ma piuttosto indeterminate. Questa idea sistemerà la questione del non valido (instant) e ci permette di assegnare in maniera ottimale uno stile al campo a seconda del suo stato di validazione.

In aggiunta a ciò, possiamo ottenere alcune funzionalità piuttosto comprensive (comprehensive) senza JavaScript. Possiamo dire in quale stato sia un campo, se è richiesto, dire se è conforme ad un certo patter con delle espressioni regolari, specificare dei valori minimi e massimi e molto altro. Ma cosa succede se questo non basta? Cosa succede se vogliamo spingerci oltre? Bene, siamo fortunati perché nel capitolo delle form HTML5 viene inoltre specificata la constraint validation API.

Constraint validation API

Insieme a tutti i nuovi attributi, tipi di input e pseudo-classi CSS3, il capitolo delle form in HTML5 specifica inoltre che una semplice API JavaScript ci permette di estendere le capacità di validazione di una form con alcuni pratici metodi, attributi ed eventi built-in. Osservate la demo aggiornata, che si aggancia ai vincoli della validation API.

Ciascun campo della form ha un nuovo attributo chiamato validity. L'attributo validity ritorna un oggetto ValidityState che rappresenta lo stato/gli stati di validità attuali di un elemento. L'oggetto ValidityState contiene diversi attributi booleani che identificano in quali stati di validità si trovi l'attuale elemento. Tipicamente, sono una serie di risposte vero/falso che dicono allo sviluppatore esattamente cosa è sbagliato in quel campo:

  • valueMissing
    Questo attributo ritorna true se un elemento obbligatorio è vuoto.
  • typeMismatch
    Questo valore si applica a tutti i nuovi attributi di tipo. Ad esempio, se un valore email non è corretto, questo attributo ritorna true.
  • patternMismatch
    Quando un elemento contiene l'attributo pattern e non è conforme alle condizioni dell'espressione regolare, questo attributo ritornerà true.
  • tooLong
    Quando un qualsiasi elemento sorpassa la sua proprietà maxlength questo attributo ritornerà true.
  • rangeUnderflow e rangeOverflow
    Se gli attributi min o max di un elemento sono al di sopra o al di sotto dei valori specificati, questo attributo ritornerà true.
  • stepMismatch
    Quando un elemento con l'attributo step non è conforme al valore step richiesto, questo attributo ritorna true.
  • valid
    Se uno qualsiasi dei valori elencati sopra ritorna true, questo attributo ritorna false per indicare che il campo non è valido. Altrimenti, se tutte le condizioni sono soddisfatte, ritornerà true.

E c'è dell'altro

L'evento invalid ha un'altra comoda feature. Sarà invocato dal campo quando è ancora non valido. In questo modo possiamo attaccare ad esso un comportamento, nel nostro caso, cambiare lo stile del campo (o dei campi) per far sì che rifletta il loro stato corrente.

Inoltre, il metodo checkValidity() può essere eseguito su ciascun campo inviduale o sull'intera form ed avere come valore di ritorno true o false. Eseguire il metodo farà scattare programmaticamente l'evento invalid per tutti i campi che non sono validi o, se eseguito su un singolo campo, solo su quell'elemento.

Portami alla demo

Prendiamo la nostra demo precedente e potenziamola con la constraint validation API. Prendendo quello che abbiamo imparato dall'articolo di Luke Wroblewski Inline Validation in Web Forms e le nostre scoperte, possiamo applicare queste idee alla nostra form per creare un'esperienza ottimale di validazione inline.

La prima cosa che possiamo sistemare è l'assegnazione istantanea dello stile di errore di un campo non valido. Piuttosto che dare immediatamente uno stile al campo per indicare che l'utente non ha soddisfatto i requisiti, aspettiamo finché si siano spostati dal campo per mostrare qualunque problema possa esserci.

Se hanno soddisfatto le richieste mentre il campo ha ancora il focus, faremo in modo che l'utente sappia istantaneamente che il campo è corretto. Facciamo ciò attaccando l'evento input per controllare che il campo sia valido. Quando lo è, aggiorniamo gli stili per rifletterlo immediatamente.

Se un campo ha valori non corretti e l'utente si sposta al campo successivo, l'evento blur controllerà la validità del campo e poi applicherà gli stili di errore per far sì che l'utente sappia che c'è qualcosa di sbagliato. Manterrà gli stili di errore finché non saranno rispettati i requisiti.

E per quel che riguarda i vecchi browser?

Tutti gli argomenti discussi sono piuttosto recenti ed il supporto da parte dei browser, sebbene sia buono, non va bene per un ambiente di produzione reale, in cui dobbiamo offrire supporto ai vecchi browser. Qui è dove diventa comodo lo script che ho scritto.

Per i browser che non supportano il capitolo delle form HTML5 e la constraint validation API, lo script simula quelle funzionalità. Per i browser che supportano queste features, lo script individua il supporto e si aggangia alla funzionalità nativa. Diamo un'occhiata alla demo ulteriormente aggiornata a cui è stato aggiunto il nuovo script. Provatela in IE o Firefox per verificare che funziona come nei browser con supporto nativo.

Browser supportati

Questo script è stato testato e funziona nei seguenti browser:

  • IE6+
  • Firefox 1+—FF4 avrà presto il supporto nativo.
  • Chrome 4+—Supporto nativo.
  • Safari 3.2+—Safari 5 ha il supporto native.
  • Opera 9.6+—Supporto nativo.

Le seguenti features sono emulate nello script:

  • Ciascun campo ha l'oggetto validity object che è live e vi informerà sullo stato corrente del campo.
  • Il metodo checkValidity() è disponibile ed indica se la form o uno specifico elemento non sono validi.
  • Gli attributi di input pattern, placeholder, required, min, max e step sono supportati.
  • Gli attributi placeholder e required sono supportati per le textarea.
  • L'attributo required è supportato per input selezionati.
  • I tipi di input email e url verranno controllati rispetto ad una espressione regolare built-in e saranno non validi finché non saranno conformi.

Un sacco di validazione!

Il supporto dei browser per le form HTML5 e per il modulo UI di CSS3 comincia a migliorare. Opera 9 ha mostrato la via implementando Web Forms 2.0 prima che fosse inglobato nel HTML5 form chapter, ma ha supportato il modulo UI di CSS3 solo a partire dalla versione 9.6. Chrome ha supportato ciò sin dalla versione 4, Safari l'ha recentemente inserito nella versione 5, Firefox dovrebbe aggiungere il supporto in una beta della versione 4 che uscirà a breve e IE9, se continuano con i loro progressi, dovrebbe avere il supporto in una delle loro preview build.

Possiamo fare alcune cose sbalorditive con i nuovi moduli e chapters di CSS3 e HTML5 rispettivamente. Man mano che migliora il supporto dei browser, questi tipi di tecniche diventano un'opzione percorribile che può essere adattata alla semplice e complessa natura della validazione delle form.

Illustrazioni: Carlo Brigatti

Share/Save/Bookmark
 

Discutiamone

Ti sembra interessante? Scrivi tu il primo commento


Cenni sull'autore

Ryan Seddon

Ryan SeddonRyan Seddon (@thecssninja) è un front end developer che vive a Melbourne, Australia. Ama trafficare con CSS e JavaScript, ed uscirsene con nuove tecniche. Potete trovare le sue scoperte ed i suoi articoli nel suo blog, The CSS Ninja.