A pochi giorni di distanza dalla pubblicazione dell'articolo Personalizzare checkbox e radio button con i CSS, Roger Johansson ha presentato sul suo blog una variante della tecnica che ha anche il pregio di essere pienamente accessibile, tenendo conto soprattutto della navigazione da tastiera tra i campi del form. Inoltre, con un uso accorto dell'altezza di linea, evita il rischio di incappare in problemi di allineamento. La presentiamo qui come un utile compendio al nostro articolo. Ecco subito la demo.
Rispetto a quest'ultimo, la tecnica sfrutta ugualmente l'uso della pseudoclasse :checked
. Il markup HTML è pertanto quasi identico a quello che abbiamo usato:
<p class="checkbox">
<input type="checkbox" id="html" value="HTML">
<label for="html">HTML</label>
</p>
[...]
<p class="radio">
<input type="radio" id="java" name="linguaggi" value="Java">
<label for="java">Java</label>
</p>
L'unica differenza è che si assegna una classe all'elemento (per noi un paragrafo) che racchiude gli input. Vedremo a cose serve tra un attimo.
Per definire l'aspetto dei controlli si usano gli sprite. Noi abbiamo usato due immagini, una per i checkbox e una per i radio button. Gli sprite hanno una larghezza di 19px e le coordinate per le varie sezioni, fondamentali per il posizionamento, sono queste:
Ogni sezione ha dunque una larghezza di 19px e un'altezza di 25px.
Con queste importanti informazioni in mano possiamo passare al CSS, non prima di aver chiarito un punto. Dal momento che la tecnica non funziona su IE8 (non supporta :checked
), Johansson ha racchiuso le regole CSS in una media query. IE8 non le supporta, per cui applicherà a checkbox e radio button l'aspetto di default. Noi abbiamo invece usato lo stesso metodo visto nell'altro articolo, ovvero l'utilizzo della pseudoclasse :not
. Il risultato è identico.
Per prima cosa si imposta una regola per il contenitore degli input (la spiegazione la lasciamo ai commenti):
.checkbox,
.radio {
/* Creiamo un contesto per il posizionamento assoluto dei controlli */
position:relative;
/* L'altezza di linea corrisponde all'altezza dell'immagine che
usiamo come sfondo del controllo */
line-height:25px;
}
Ora posizioniamo assolutamente e nascondiamo con opacity:0
i controlli originari:
/*
Gli input sono resi trasparenti invece che nascosti per consentire
comunque il click sui browser che non supportano la le label cliccabili
come Safari su iOS 5 e precedenti.
*/
p:not(#foo) > input[type="checkbox"],
p:not(#foo) > input[type="radio"] {
position:absolute;
/* Larghezza e altezza corrispondono a quelle dell'immagine */
width:19px;
height:25px;
/* Resettiamo tutto ciò che può interferire con le dimensioni */
overflow:hidden;
margin:0;
padding:0;
border:0;
outline:0;
opacity:0;
}
Ora dobbiamo ricreare il controllo. Usiamo il contenuto generato sulle label. Cominciamo con i checkbox:
/*
Inseriamo uno pseudoelemento per ciascuna label e assegniamo come
sfondo un'immagine. Usiamo inline-block per poter sfruttare vertical-align
ai fini dell'allineamento.
*/
p:not(#foo) > input[type="checkbox"] + label:before {
content:" ";
display:inline-block;
/* Larghezza e altezza corrispondono a quelle dell'immagine */
width:19px;
height:25px;
margin-right:4px;
background:url(check-sprite.png) no-repeat;
vertical-align:top;
}
Stessa cosa per i radio button, cambia solo l'immagine di sfondo:
p:not(#foo) > input[type="radio"] + label:before {
content:" ";
display:inline-block;
/* Larghezza e altezza corrispondono a quelle dell'immagine */
width:19px;
height:25px;
margin-right:4px;
background:url(radio-sprite.png) no-repeat;
vertical-align:top;
}
Per concludere, definiamo i vari stati (iniziale, focus, attivato, focus su attivato) e a seconda di ciascuno modifichiamo la posizione dello sfondo sulla base delle coordinate viste in precedenza. Prima per i checkbox:
p:not(#foo) > input[type="checkbox"] + label:before {
background-position:0 0px;
}
p:not(#foo) > input[type="checkbox"]:focus + label:before {
background-position:0 -25px;
}
p:not(#foo) > input[type="checkbox"]:checked + label:before {
background-position:0 -50px;
}
p:not(#foo) > input[type="checkbox"]:checked:focus + label:before {
background-position:0 -75px;
}
Poi per i radio button:
p:not(#foo) > input[type="radio"] + label:before {
background-position:0 0px;
}
p:not(#foo) > input[type="radio"]:focus + label:before {
background-position:0 -25px;
}
p:not(#foo) > input[type="radio"]:checked + label:before {
background-position:0 -50px;
}
p:not(#foo) > input[type="radio"]:checked:focus + label:before {
background-position:-0 -75px;
}