Botón on/off o switch en HTML y CSS
Con la llegada de los dispositivos móviles se han hecho muy populares el uso de botones con dos opciones, también llamadas botones on/off o switch. Un elemento que nos proporciona 2 estados: encendido/apagado, abierto/cerrado, etc. No existe ninguna ayuda nativa dentro del estándar HTML, por lo que será necesario hacer un poco de magia con los input checkbox.
DEMO
HTML
El secreto radica en disponer de un checkbox oculto, para disponer del estado checked y un label que proporcionará la forma del botón.
Fíjate en el aria-label: como el label está vacío (es pura decoración), el checkbox no tendría nombre y un lector de pantalla anunciaría solo "casilla, sin marcar", sin pista de qué enciende o apaga. El aria-label le da ese nombre.
<div class="switch-button">
<!-- Checkbox -->
<input type="checkbox" name="switch-button" id="switch-label" aria-label="Interruptor" class="switch-button__checkbox">
<!-- Botón -->
<label for="switch-label" class="switch-button__label"></label>
</div>
CSS
Jugaremos con el before del label (o el botón) con el objetivo de crear el circulo blanco, mientras que al propio label lo usaremos para añadir nuestro color de fondo (rojo o verde).
Cuando sea pulsado el label automáticamente el checkbox cambiará a checked (pulsado), haciendo sencilla la tarea de cambiar su posición.
Para ocultar el checkbox evita display: none: lo sacaría del orden de tabulación y del árbol de accesibilidad, y el interruptor sería imposible de usar con teclado o lector de pantalla. En su lugar lo reducimos a un píxel recortado: sigue existiendo, recibe el foco y Espacio lo conmuta. Y como el input es invisible, el anillo de foco lo dibujamos sobre el label con :focus-visible.
:root {
--color-green: #00a878;
--color-red: #fe5e41;
--color-button: #fdffff;
--color-black: #000;
}
.switch-button {
display: inline-block;
}
/* Oculto visualmente, pero sigue en el teclado y en el lector de pantalla */
.switch-button .switch-button__checkbox {
position: absolute;
width: 1px;
height: 1px;
overflow: hidden;
clip: rect(0 0 0 0);
white-space: nowrap;
}
/* Anillo de foco sobre el botón al navegar con teclado */
.switch-button .switch-button__checkbox:focus-visible + .switch-button__label {
outline: 2px solid var(--color-black);
outline-offset: 2px;
}
.switch-button .switch-button__label {
background-color: var(--color-red);
width: 5rem;
height: 3rem;
border-radius: 3rem;
display: inline-block;
position: relative;
}
.switch-button .switch-button__label:before {
transition: .2s;
display: block;
position: absolute;
width: 3rem;
height: 3rem;
background-color: var(--color-button);
content: '';
border-radius: 50%;
box-shadow: inset 0px 0px 0px 1px var(--color-black);
}
.switch-button .switch-button__checkbox:checked + .switch-button__label {
background-color: var(--color-green);
}
.switch-button .switch-button__checkbox:checked + .switch-button__label:before {
transform: translateX(2rem);
}
Completo
Todo unido quedaría de la siguiente forma.
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width" />
<style type="text/css" media="screen">
:root {
--color-green: #00a878;
--color-red: #fe5e41;
--color-button: #fdffff;
--color-black: #000;
}
.switch-button {
display: inline-block;
}
/* Oculto visualmente, pero sigue en el teclado y en el lector de pantalla */
.switch-button .switch-button__checkbox {
position: absolute;
width: 1px;
height: 1px;
overflow: hidden;
clip: rect(0 0 0 0);
white-space: nowrap;
}
/* Anillo de foco sobre el botón al navegar con teclado */
.switch-button .switch-button__checkbox:focus-visible + .switch-button__label {
outline: 2px solid var(--color-black);
outline-offset: 2px;
}
.switch-button .switch-button__label {
background-color: var(--color-red);
width: 5rem;
height: 3rem;
border-radius: 3rem;
display: inline-block;
position: relative;
}
.switch-button .switch-button__label:before {
transition: .2s;
display: block;
position: absolute;
width: 3rem;
height: 3rem;
background-color: var(--color-button);
content: '';
border-radius: 50%;
box-shadow: inset 0px 0px 0px 1px var(--color-black);
}
.switch-button .switch-button__checkbox:checked + .switch-button__label {
background-color: var(--color-green);
}
.switch-button .switch-button__checkbox:checked + .switch-button__label:before {
transform: translateX(2rem);
}
</style>
</head>
<body>
<div class="switch-button">
<input type="checkbox" name="switch-button" id="switch-label" aria-label="Interruptor" class="switch-button__checkbox">
<label for="switch-label" class="switch-button__label"></label>
</div>
</body>
</html>
Un último apunte: si el interruptor controla algo que se aplica al instante (modo oscuro, notificaciones...), puedes añadirle role="switch" al input para que los lectores de pantalla lo anuncien como interruptor en vez de como casilla.
Si te ha gustado, por favor deja un comentario con tus impresiones. Y sino... pues también.
Este trabajo está bajo una licencia Attribution-NonCommercial-NoDerivatives 4.0 International.
Ayúdame a seguir escribiendo
Cada café me da un empujón para escribir el siguiente artículo.
¡Claro, te invito!
Comentarios
Todavía no hay ningún comentario.