
Hablemos de botones deshabilitados. Específicamente, veamos por qué los usamos y cómo podemos hacerlo mejor que los tradicionales. disabled
atributo en HTML (p. ej. <button disabled>
) para marcar un botón como deshabilitado.
Hay muchos casos de uso en los que un botón deshabilitado tiene mucho sentido, y llegaremos a esas razones en un momento. Pero a lo largo de este artículo, veremos un formulario que nos permite agregar una cantidad de boletos a un carrito de compras.
Este es un buen ejemplo de línea de base porque existe una situación clara para deshabilitar el botón “Agregar al carrito”: cuando no hay boletos para agregar al carrito.
Pero primero, ¿por qué desactivar los botones?
Evitar que las personas realicen una acción no válida o no disponible es la razón más común por la que podemos buscar un botón deshabilitado. En la demostración a continuación, solo podemos agregar boletos si el número de boletos que se agregan al carrito es mayor que cero. Darle una oportunidad:
Permítame omitir la explicación del código en esta demostración y centrar nuestra atención en lo que es importante: el botón “Agregar al carrito”.
<button type="submit" disabled="disabled">
Add to cart
</button>
Este botón está desactivado por el disabled
atributo. (Tenga en cuenta que este es un atributo booleano, lo que significa que se puede escribir como disabled
o disabled="disabled"
.)
Todo parece estar bien … entonces, ¿qué tiene de malo?
Bueno, para ser honesto, podría terminar el artículo aquí pidiéndole que no use botones deshabilitados porque apestan, y en su lugar use mejores patrones. Pero seamos realistas: a veces, deshabilitar un botón es la solución que tiene más sentido.
Dicho esto, para este propósito de demostración, pretendemos que deshabilitar el botón “Agregar al carrito” es la mejor solución (Alerta de spoiler: no es). Todavía podemos usarlo para aprender cómo funciona y mejorar su usabilidad en el camino.
Tipos de interacciones
Me gustaría aclarar lo que quiero decir con los botones deshabilitados que se pueden usar. Puede pensar, si el botón está desactivado, no debería ser utilizable, así que … ¿cuál es el problema? Tengan paciencia conmigo.
En la web, hay varias formas de interactuar con una página. Usar un mouse es uno de los más comunes, pero hay otros, como las personas videntes que usan el teclado para navegar debido a una discapacidad motora.
Intente navegar por la demostración anterior utilizando solo el Tab
clave para seguir adelante y Tab
+ Shift
para ir hacia atrás. Notarás cómo se omite el botón deshabilitado. El enfoque va directamente de la entrada del ticket al enlace de “términos ficticios”.
Utilizando el Tab
, cambia el enfoque de la entrada al enlace, omitiendo el botón “Agregar al carrito”.
Hagamos una pausa por un segundo y recapitulemos la razón que nos llevó a deshabilitar el botón en primer lugar en comparación con lo que realmente habíamos logrado.
Es común asociar “interactuar” con “hacer clic”, pero son dos conceptos diferentes. Sí, hacer clic es un tipo de interacción, pero es solo uno entre otros, como desplazarse y enfocarse.
En otras palabras…
Todos los clics son interacciones, pero no todas las interacciones son clics.
Nuestro objetivo es evitar el clic, pero utilizando disabled
, estamos evitando no solo el clic, sino también el enfoque, lo que significa que podríamos estar haciendo tanto daño como bien. Claro, este comportamiento puede parecer inofensivo, pero genera confusión. Las personas con una discapacidad cognitiva pueden tener dificultades para comprender por qué no pueden enfocar el botón.
En la siguiente demostración, modificamos un poco el diseño. Si usa un mouse y pasa el cursor sobre el botón de envío, se muestra una información sobre herramientas que explica por qué el botón está deshabilitado. ¡Genial!
Pero si usa solo el teclado, no hay forma de ver esa información sobre herramientas porque el botón no se puede enfocar con disabled
. Lo mismo ocurre con los dispositivos táctiles. ¡Ay!
Con el mouse, la información sobre herramientas en el botón “Agregar al carrito” es visible al pasar el mouse. Pero falta la información sobre herramientas al usar el Tab
llave.
Permítame saltar una vez más más allá de la explicación del código. Recomiendo encarecidamente leer “Información sobre herramientas inclusiva” de Haydon Pickering y “Información sobre herramientas en el momento de WCAG 2.1” de Sarah Higley para comprender completamente el patrón de información sobre herramientas.
ARIA al rescate
El disabled
atributo en un <button>
está haciendo más de lo necesario. Este es uno de los pocos casos que conozco en los que un atributo HTML nativo puede hacer más daño que bien. El uso de un atributo ARIA puede hacer un mejor trabajo, lo que nos permite agregar no solo el enfoque en el botón, sino hacerlo de manera consistente para crear una experiencia inclusiva para más personas y casos de uso.
El disabled
atributo se correlaciona con aria-disabled="true"
. Prueba la siguiente demostración, nuevamente, usando solo el teclado. Observe cómo el botón, aunque está marcado como deshabilitado, sigue siendo accesible mediante el enfoque y activa la información sobre herramientas.
Utilizando el Tab
, el botón “Agregar al carrito” está enfocado y muestra la información sobre herramientas.
Genial, ¿eh? ¡Un pequeño ajuste para una gran mejora!
Pero aún no hemos terminado. La advertencia aquí es que todavía necesitamos evitar el clic mediante programación, usando JavaScript.
elForm.addEventListener('submit', function (event) {
event.preventDefault(); /* prevent native form submit */
const isDisabled = elButtonSubmit.getAttribute('aria-disabled') === 'true';
if (isDisabled || isSubmitting) {
// return early to prevent the ticket from being added
return;
}
isSubmitting = true;
// ... code to add to cart...
isSubmitting = false;
})
Es posible que esté familiarizado con este patrón como una forma de evitar que los clics dobles envíen un formulario dos veces. Si estuvieras usando el disabled
atributo por esa razón, preferiría no hacerlo porque eso causa la pérdida temporal del enfoque del teclado mientras se envía el formulario.
La diferencia entre disabled
y aria-disabled
Podrías preguntar: si aria-disabled
no evita el clic de forma predeterminada, ¿cuál es el punto de usarlo? Para responder a eso, debemos comprender la diferencia entre ambos atributos:
Característica / Atributo | disabled |
aria-disabled="true" |
---|---|---|
Evitar el clic | ✅ | ❌ |
Prevenir hover | ❌ | ❌ |
Prevenir el enfoque | ✅ | ❌ |
Estilos CSS predeterminados | ✅ | ❌ |
Semántica | ✅ | ✅ |
La única superposición entre los dos es semántica. Ambos atributos anunciarán que el botón está desactivado, y eso es bueno.
Contrariamente a la disabled
atributo, aria-disabled
se trata de semántica. Los atributos ARIA nunca cambian el comportamiento o los estilos de la aplicación de forma predeterminada. Su único propósito es ayudar a las tecnologías de asistencia (por ejemplo, lectores de pantalla) a anunciar el contenido de la página de una manera más significativa y sólida.
Hasta ahora, hemos hablado de dos tipos de personas, las que hacen clic y las que Tab
. Ahora hablemos de otro tipo: las personas con discapacidad visual (por ejemplo, ceguera, baja visión) que utilizan lectores de pantalla para navegar por la web.
Personas que usan lectores de pantalla, a menudo prefieren navegar por los campos del formulario usando la tecla Tab. Ahora observe cómo VoiceOver en macOS omite completamente el disabled
botón.
El lector de pantalla VoiceOver omite el botón “Agregar al carrito” al usar el Tab
llave.
Una vez más, esta es una forma mínima. En uno más largo, buscar un botón de envío que no está allí de inmediato puede ser molesto. Imagine un formulario en el que el botón de envío está oculto y solo es visible cuando lo completa por completo. Eso es lo que sienten algunas personas cuando disabled
se utiliza el atributo.
Afortunadamente, los botones con disabled
no son totalmente inalcanzables para los lectores de pantalla. Todavía puede navegar por cada elemento individualmente, uno por uno, y eventualmente encontrará el botón.
El lector de pantalla VoiceOver puede encontrar y anunciar el botón “Agregar al carrito”.
Aunque es posible, esta es una experiencia molesta. Por otro lado, con aria-disabled
, el lector de pantalla enfocará el botón normalmente y anunciará correctamente su estado. Tenga en cuenta que el anuncio es ligeramente diferente entre los lectores de pantalla. Por ejemplo, NVDA y JWAS dicen “botón, no disponible”, pero VoiceOver dice “botón, atenuado”.
El lector de pantalla VoiceOver puede encontrar el botón “Agregar al carrito” usando Tab
clave debido a aria-disabled
.
Hice un mapa de cómo ambos atributos crean diferentes experiencias de usuario en función de las herramientas que acabamos de usar:
Herramienta / Atributo | disabled |
aria-disabled="true" |
---|---|---|
Ratón o toque | Evita el clic de un botón. | Requiere JS para evitar el clic. |
Pestaña | No se puede enfocar el botón. | Capaz de enfocar el botón. |
Lector de pantalla | El botón es difícil de localizar. | El botón se encuentra fácilmente. |
Entonces, las principales diferencias entre ambos atributos son:
disabled
podría omitir el botón al usar elTab
clave, lo que lleva a confusión.aria-disabled
todavía enfocará el botón y anunciará que existe, pero que aún no está habilitado; de la misma manera que lo percibiría visualmente.
Este es el caso en el que es importante reconocer la sutil diferencia entre accesibilidad y usabilidad. La accesibilidad es una medida de que alguien puede usar algo. La usabilidad es una medida de lo fácil que es usar algo.
Dado eso, es disabled
¿accesible? Si. ¿Tiene buena usabilidad? No lo creo.
¿Podemos hacerlo mejor?
No me sentiría bien conmigo mismo si terminara este artículo sin mostrarte la solución inclusiva real para nuestro ejemplo de formulario de ticket. Siempre que sea posible, no use botones deshabilitados. Permita que las personas hagan clic en él en cualquier momento y, si es necesario, muestre un mensaje de error como comentario. Este enfoque también resuelve otros problemas:
- Menos fricción cognitiva: Permita que las personas envíen el formulario en cualquier momento. Esto elimina la incertidumbre de si el botón está deshabilitado en primer lugar.
- Contraste de color: Aunque un botón deshabilitado no necesita cumplir con el contraste de color WCAG 1.4.3, creo que debemos garantizar que un elemento sea siempre visible de manera adecuada independientemente de su estado. Pero eso es algo de lo que no tenemos que preocuparnos ahora porque el botón ya no está desactivado.
Pensamientos finales
El disabled
atributo en <button>
Es un caso peculiar en el que, aunque es muy conocido por la comunidad, puede que no sea el mejor enfoque para resolver un problema en particular. No me malinterpretes porque no estoy diciendo disabled
siempre es malo. Todavía hay algunos casos en los que todavía tiene sentido usarlo (por ejemplo, paginación).
Para ser honesto, no veo el disabled
atributo exactamente como un problema de accesibilidad. Lo que me preocupa es más un problema de usabilidad. Al cambiar el disabled
atributo con aria-disabled
, podemos hacer que la experiencia de alguien sea mucho más agradable.
Este es un paso más en mi viaje hacia la accesibilidad web. A lo largo de los años, he descubierto que la accesibilidad es mucho más que cumplir con los estándares web. Tratar con las experiencias de los usuarios es complicado y la mayoría de las situaciones requieren hacer concesiones y compromisos en la forma en que abordamos una solución. No existe una fórmula mágica para una accesibilidad perfecta.
Nuestro deber como creadores web es buscar y comprender las diferentes soluciones disponibles. Solo entonces podremos tomar la mejor decisión posible. No tiene sentido pretender que los problemas no existen.
Al final del día, recuerde que nada le impide hacer de la Web un lugar más inclusivo.
Prima
¿Aún allí? Permítanme mencionar dos últimas cosas sobre esta demostración que creo que valen la pena:
1. Live Regions anunciará contenido dinámico
En la demostración, dos partes del contenido cambiaron dinámicamente: el botón de envío del formulario y la confirmación de éxito (“Agregado [X] ¡Entradas!”).
Sin embargo, estos cambios se perciben visualmente para las personas con discapacidad visual que utilizan lectores de pantalla, pero esa no es la realidad. Para resolverlo, debemos convertir esos mensajes en Regiones en vivo. Aquellos permiten que las tecnologías de asistencia escuchen los cambios y anuncien los mensajes actualizados cuando sucedan.
Hay un .sr-only
clase en la demostración que oculta un <span>
que contiene un mensaje de carga, pero permite que los lectores de pantalla lo anuncien. En este caso, aria-live="assertive"
se aplica a la <span>
y contiene un mensaje significativo después de que se envía el formulario y está en proceso de carga. De esta forma, podemos anunciar al usuario que el formulario está funcionando y que tenga paciencia mientras se carga. Además, hacemos lo mismo con el elemento de comentarios del formulario.
<button type="submit" aria-disabled="true">
Add to cart
<span aria-live="assertive" class="sr-only js-loadingMsg">
<!-- Use JavaScript to inject the the loading message -->
</span>
</button>
<p aria-live="assertive" class="formStatus">
<!-- Use JavaScript to inject the success message -->
</p>
Tenga en cuenta que el aria-live
El atributo debe estar presente en el DOM desde el principio, incluso si el elemento aún no contiene ningún mensaje; de lo contrario, es posible que las tecnologías de asistencia no funcionen correctamente.
Formulario enviar mensaje de retroalimentación anunciado por el lector de pantalla.
Hay mucho más que contarte sobre este pequeño aria-live
atributo y las grandes cosas que hace. También hay trampas. Por ejemplo, si se aplica incorrectamente, el atributo puede hacer más daño que bien. Vale la pena leer “Uso de aria-live” de Ire Aderinokun y “Cargando esqueletos” de Adrian Roselli para comprender mejor cómo funciona y cómo usarlo.
2. No utilizar pointer-events
para evitar el clic
Esta es una implementación alternativa (e incorrecta) que he visto en la web. Esto usa pointer-events: none;
en CSS para evitar el clic (sin ningún atributo HTML). Por favor no hagas esto. Aquí hay un bolígrafo feo que, con suerte, demostrará por qué. Repito, no hacer esto.
Aunque ese CSS efectivamente evita un clic del mouse, recuerde que no evitará el enfoque y la navegación con el teclado, lo que puede generar resultados inesperados o, lo que es peor, errores.
En otras palabras, usar esta regla CSS como estrategia para evitar un clic no tiene sentido (¿lo entiendes?). 😉