Checkbox personalizada y accesible sólo con CSS

Dibujo a mano alzada de dos casillas de verificación
Imagen de Oliver Tacke - modificada.

Con CSS podemos dar estilo a prácticamente cualquier elemento de nuestra web. Y digo prácticamente porque hay algunos elementos "rebeldes" que se nos resisten. Entre ellos se encuentran las checkboxes (casillas de verificación) y los botones de tipo radio.

Puede que en algunos diseños el estilo por defecto de una checkbox quede perfectamente integrado, pero en la mayoría de los casos no es así. Por ello se ha tendido a crear este tipo de controles con elementos div o span, perdiendo por el camino la semántica, la accesibilidad y teniendo que recurrir a javascript para darles la funcionalidad requerida.

En este tutorial vamos a ver una forma de conseguir dar estilo a una checkbox, manteniendo los aspectos básicos de este elemento y sin tener que recurrir a javascript, porque CSS3 es suficiente para suplir lo que debería ser un estándar, poder dar estilo a todos y cada uno de los elementos de HTML.

Malas prácticas a la hora de dar estilo

De forma recurrente se ha usado CSS inadecuadamente para dar estilo a determinados elementos. En general se han usado elementos genéricos y recurrido a técnicas innecesarias cuando frente a nosotros teníamos el elemento adecuado para hacerlo. Un ejemplo muy claro es la creación de botones bien mediante elementos div o span cuando para ello tenemos el elemento button.

Con este tipo de prácticas lo único que conseguimos es cargarnos de trabajo innecesario pues tenemos que dotar al nuevo elemento creado de su supuesta funcionalidad mediante javascript, asignarle un nuevo rol por medio de WAI-ARIA, y hacer que sea accesible mediante teclado con la propiedad tabindex. Como decía antes, trabajo innecesario, ya que usando el elemento correcto todo este trabajo ya está hecho.

La cosa cambia cuando ante nosotros tenemos un elemento al cual no es posible darle otro estilo mediante CSS, entonces parece inevitable el uso de técnicas que la propia W3C recomienda no usar. Si embargo con CSS3 y un poco de imaginación podemos conseguir nuestra meta y para ello sólo necesitamos usar el elemento input type="checkbox". ¿Pero cómo?.

Parece extraño que la solución para dar estilo a una checkbox, un elemento al que no podemos darle estilo mediante CSS, se usar la propia checkbox, pero ya hemos usado esta técnica en este blog, por ejemplo cuando creamos un icono animado estilo hamburguesa en CSS puro. Usando la conocida técnica del "checkbox hack".

Para ello vamos a necesitar una checkbox, una etiqueta label que de todas formas habría que usar para dar la información referente a la casilla de verificación y el pseudo-elemento :checked.

Una checkbox en CSS puro

Lo que vamos a hacer es muy sencillo. Vamos a usar la checkbox únicamente como una marcador binario, con lo cual vamos a ocultarla pues no nos sirve par nada mas, eso sí, hay que ocultarla correctamente para no perder la accesibilidad.

Después usaremos la etiqueta label, a parte de para dar la información referente a la checbox, para crear nuestra nueva checkbox, usando el pseudo-elemento :checked para dibujarla, bien seleccionada o de-seleccionada.

Vamos a comenzar con el marcado en HTML, que como verás es muy sencillo.


<div>
  <input type="checkbox" id="box1">
  <label for="box1">Checkbox 1</label>
</div>

Lo único a tener en cuenta en este marcado es asociar las etiquetas input y label mediante los atributos id y for. Ambos deben tener el mismo valor.

Lo primero en cuanto a estilo es eliminar algunos valores estándar, como los márgenes interiores y exteriores, y también cambiaremos el modelo de caja. Así trabajaremos más a gusto.


*,
*:before,
*:after {
    box-sizing: border-box;
    margin: 0;
    padding: 0;
}

El siguiente paso es ocultar nuestra checkbox, para esta caso vamos a usar la propiedad opacity, aunque también serviría clip. Y de paso vamos a dibujar la nueva checkbox valiéndonos de la etiqueta label.


div {
    position: relative;

    height: 2em;
    margin-bottom: 1em;
}

input[type*='checkbox'] {
    opacity: 0;
}

label {
    line-height: 2em;

    position: absolute;
    left: 0;

    margin-bottom: 10em;
    padding: 0 1.5em 0 2.5em;
}

label:before {
    font-size: 2em;
    line-height: .5em;

    position: absolute;
    left: 0;

    width: 1em;
    height: 1em;

    content: '';
    text-align: center;

    border: .2em solid #eb7260;
}

Con esto lo que nos queda es dibujar nuestra checkbox cuando su estado es seleccionada, para ello usaremos el pseudo-elemento :checked. Voy a usar Font-Awesome para dibujar la típica "uve" de selección, así que lo primero es referenciar esta fuente. Lo vamos a hacer directamente en nuestro CSS.


@import url('//netdna.bootstrapcdn.com/font-awesome/3.2.1/css/font-awesome.min.css');

Y ahora dibujamos nuestra checkbox en el estado seleccionada.


input[type*='checkbox']:checked + label:before {
    font-family: FontAwesome;

    content: '\f00c';
}

Por último, y sólo para hacerla más accesible desde teclado, vamos a añadir un detalle más para saber en qué momento nuestra checkbox tiene el foco, valiéndonos nuevamente de uno de los iconos de Font-Awesome.


input[type*='checkbox']:focus + label:after {
    font-family: FontAwesome;

    position: absolute;
    right: 0;

    content: '\f177';
}

¿Es realmente accesible?

Para comprobarlo lo único que tenemos que hacer es ver lo que hemos hecho. Si te fijas bien estamos usando los mismos elementos que usaríamos si usásemos una checkbox por defecto, un elemento input type="checkbox" y un elemento label, con lo cual mantenemos la semántica.

En ningún momento perdemos la funcionalidad, ya que realmente usamos la checkbox en todo momento, tanto seleccionándola como deseleccionándola, tan sólo la hemos ocultado y aprovechamos la etiqueta label para volver a dibujarla, pero en realidad todo funciona igual que usando una checkbox por defecto.

Sigue siendo accesible por teclado y también será anunciada si usamos algún tipo de screenreader, puesto que sólo la hemos ocultado, y lo hemos hecho correctamente.

Y por último, hemos añadido un detalle más que ayuda a saber donde tenemos el foco si usamos la navegación mediante teclado, puesto que la representación del foco en los navegadores, en muchas ocasiones, es demasiado sutil para el usuario, sobre todo si usamos colores claros en nuestro diseño. Nunca está demás comprobar si realmente vemos donde está o no el foco usando la navegación por teclado.

Puedes ver un ejemplo con tres checkboxes para que veas que todo funciona tal y como he dicho en el pen que he preparado para este tutorial. Además así podrás trastear con él todo lo que quieras y ver las posibilidades que tienes para dar estilo a una checkbox.

See the Pen Custom & accessible checkbox in pure CSS by amram (@amram1977) on CodePen.