¿Cuándo un botón no es un botón?

Publicado: 2022-03-10
Resumen rápido ↬ No todo lo que es redondo y destaca se considera botón. En este artículo, Vadim explica cómo puede crear un botón interactivo adecuado para sus usuarios, uno que no debe confundirse con nada más.

Digamos que tiene una parte de una interfaz en la que el usuario hace clic y algo sucede. Suena como un botón para mí, pero llamémoslo "cosa que hace clic" por ahora. Lo sé, estás seguro de que también es un botón: es redondeado y se destaca con un bonito color tomate, invitando a interactuar con él. Pero pensemos en ello por un momento. Ahorrará tiempo a largo plazo, lo prometo.

Algo parecido a un botón de tomate con el texto "Algo".
Diseño para su 'cosa clicky' (Vista previa grande)

¿Qué pasaría si el texto en este clic fuera "Leer más" y al hacer clic en él llevara al usuario a un artículo en otra página? Mmm. ¿Y si hubiera una palabra subrayada en azul, "Cerrar", que cierra el cuadro de diálogo emergente? ¿Es un enlace solo porque es azul y está subrayado? Por supuesto que no.

Enlace similar a un botón y botón similar a un enlace
El dilema del enlace o el botón (vista previa grande)
¡Más después del salto! Continúe leyendo a continuación ↓

¡Guau! Parece que no hay forma de saber si es un enlace o un botón con solo mirarlo. ¡Eso es una locura! Necesitamos entender qué hace esta cosa antes de elegir el elemento correcto. Pero, ¿qué pasa si todavía no sabemos lo que hace o simplemente estamos confundidos? Bueno, hay un diagrama de flujo útil para nosotros:

Diagrama de flujo: Es un botón. Si no, entonces es un enlace. Eso es todo.
Un diagrama de flujo científico para elegir el elemento correcto (vista previa grande)
  1. es un botón
  2. Si no, entonces es un enlace.
  3. Eso es todo.

Entonces, ¿todo es un botón? No, pero siempre puede comenzar con un botón para casi cualquier elemento en el que se pueda hacer clic o interactuar de manera similar. Y si le falta algo, como la navegación a otra página, use un enlace en su lugar. Y no, un puntero no es una razón para hacerlo <a href> . Tenemos cursor: pointer para eso.

Botón de tomate enfocado con el texto "Algo" en él
No olvide proporcionar estilos de enfoque. (Vista previa grande)

De acuerdo, es un <button> ; estamos de acuerdo en eso. Pongámoslo en nuestra plantilla y diseñémoslo de acuerdo con el diseño: algo de relleno, redondeo, relleno de tomate, texto blanco e incluso algunos estilos de enfoque. Oh, eso es muy amable de tu parte.

 <button type="button" class="button"> Something </button> <style> .button { display: inline-block; padding: 10px 20px; border-radius: 20px; background-color: tomato; color: white; } .button:focus { outline: none; box-shadow: 0 0 0 5px #006AE3; } </style>

Eso no tomó mucho tiempo. Querías construirlo rápidamente y almorzar porque tienes hambre. Bien, veamos cómo se ve y empecemos.

Botón de tomate de aspecto feo, representado en un navegador
A veces el navegador no es tu mejor amigo. (Vista previa grande)

¡Ay Dios mío! Algo anda mal con el navegador. ¿Por qué este botón es tan feo? El texto es pequeño, a pesar de que hemos establecido explícitamente el body en 16px , e incluso la font-family es incorrecta. El borde redondeado con una pseudosombra tonta es tan retro que ni siquiera es una tendencia todavía.

Ahh, es el estilo predeterminado del navegador. Debe deshacerlo con cuidado o incluso agregar Normalize.css o Reset.css... o simplemente puede usar un <div> y olvidarse de él. ¿No es por lo que te pagan por resolver problemas rápidamente? Tienes hambre y esto no está ayudando en absoluto. Pero usted es un profesional: recompóngase y piense.

¿Cuál es la diferencia entre un <button> y un <div> de todos modos? Un <button> incorporado es un elemento interactivo, lo que significa que se puede interactuar con él. Eso es profundo. Puede hacer clic en él, puede concentrarse en él usando un teclado y también transmite una función de button accesible a los lectores de pantalla, lo que permite que los usuarios entiendan que es un botón.

¡Impresionante! No solo conoce el elemento <button> de HTML, sino que también sabe un par de cosas sobre ARIA y la compatibilidad con lectores de pantalla. Es posible que incluso haya probado VoiceOver o NVDA para probar qué tan accesibles son sus interfaces.

Entonces, has decidido hacer un truco. No alterará el estilo del navegador y hará que el elemento se vea como un botón interactivo adecuado para los usuarios que lo necesiten. ¡Eso es inteligente!

 <div class="button" tabindex="0" role="button"> Something </div>

Ahora no solo se ve bien, sino que se puede enfocar a través del teclado gracias al tabindex="0" , y los lectores de pantalla lo tratarán como un botón adecuado porque sabiamente le ha agregado role="button" . Git commit && push entonces! Hay algunas tareas adicionales para esta cosa, pero hemos terminado con el estilo. ¿Qué podría salir mal? Hora de almorzar. ¡Genial, vamos!

Una hora más tarde…

¡Ese fue un buen almuerzo! Volvamos a nuestra cosa clicky. Necesitamos completar algunas tareas antes de continuar. Veamos... Necesitamos llamar a una función doSomething una vez que se hace clic en el botón, y debería haber una forma de desactivar el botón para que no se pueda hacer clic. Suena fácil. Agreguemos un detector de eventos a este botón:

 <script> const buttons = document.querySelectorAll('.button'); [...buttons].forEach(button => { button.addEventListener('click', doSomething); }); function doSomething() { console.log('Something!'); } </script>

Hecho. El usuario ahora puede hacer clic con el mouse en el escritorio y tocarlo con un dedo en una pantalla táctil. Un evento de clic se disparará de manera confiable, ¡y verá mucho Algo! en tu consola. ¿Cuál es la siguiente tarea?

¡Esperar! Necesitamos asegurarnos de que funcione de la misma manera para los usuarios de teclado. Debido a que tenemos este tabindex="0" en el botón, se puede enfocar, y una vez que se enfoca, los usuarios deberían poder presionar la barra espaciadora o la tecla "Entrar" para activar lo que hayamos adjuntado.

Por lo tanto, debemos adjuntar otro detector de eventos para capturar todas las teclas y activaremos nuestra función solo para ciertas teclas. Gracias a Dios que los dispositivos táctiles son lo suficientemente inteligentes como para convertir todos los toques en clics; de lo contrario, también tendríamos que adjuntar un montón de eventos táctiles.

 <script> const buttons = document.querySelectorAll('.button'); [...buttons].forEach(button => { button.addEventListener('click', doSomething); button.addEventListener('keyup', (event) => { if (event.key == 'Enter' || event.key == ' ') { doSomething(); } }); }); function doSomething() { console.log('Something!'); } </script>

¡Uf! Ahora nuestro clicky es totalmente accesible desde el teclado. ¡Estoy tan orgulloso de ti! Y JavaScript es realmente mágico: ¿qué haríamos sin él?

Muy bien, cuál es la última tarea: "El botón debe tener un estado deshabilitado que cambie su apariencia y comportamiento a algo insensible". ¿Entumecido? Supongo que eso significa algo gris y que no responde a la interacción. Bien, agreguemos un estado en la hoja de estilo usando la denominación BEM.

 <div class="button button--disabled" tabindex="0" role="button"> Something </div> <style> .button--disabled { background-color: #9B9B9B; } </style> 
Botón gris con el estado desactivado aplicado
Este botón se ve cómodamente entumecido. (Vista previa grande)

Eso me parece cómodamente adormecido . Siempre que sea necesario deshabilitar el botón, agregaremos el modificador button--disabled para hacerlo gris. Pero todavía no está lo suficientemente adormecido: todavía se puede enfocar y activar tanto con un puntero como desde el teclado.

Diablos, esto se está complicando.

No solo eso, sino que el botón no debería ser accesible en el orden de tabulación, lo que significa que el atributo tabindex no debería estar allí. Y debemos verificar si el botón tiene el estado deshabilitado y luego dejar de activar nuestra función. Además, este modificador podría aplicarse dinámicamente. Si bien no es un problema para CSS hacer coincidir elementos con selectores sobre la marcha y aplicar estilos, es posible que necesitemos algún tipo de observador de mutaciones para activar otros cambios para este botón.

¿Yo se, verdad? Pensamos que este sería un pequeño botón simple que activa una función y tiene un estado deshabilitado. Hemos tratado de hacerlo bien con la accesibilidad y todo eso, y ahora estamos en lo más profundo de este agujero de conejo.

Tomemos algo de comida para llevar. No estaremos en casa para cenar cuando terminemos y probemos correctamente esto. ¡Maldito W3C! ¿Por qué no intentan hacernos la vida más fácil? ¡Como si se preocuparan por nosotros!

De hecho, lo hacen…

Retrocedamos unos pasos antes de meternos en este lío. ¿Por qué no intentamos hacer estas cosas usando el elemento <button> ? Tiene algunos trucos útiles bajo la manga, no solo los feos estilos del navegador. Ah, y no olvide type="button" : no desea que el botón "Cerrar" de la ventana emergente envíe accidentalmente el formulario, porque type="submit" es el valor predeterminado.

Aparentemente, cuando el <button> está enfocado y se presiona la barra espaciadora o la tecla "Entrar", activará el evento de click , tal como lo hacen los dispositivos móviles cuando reciben toques, palmaditas, lamidas o cualquier otra cosa que sean capaces de recibir. hoy dia. ¡Un detector de eventos menos en nuestro código! Agradable.

 // A click is enough! button.addEventListener('click', doSomething);

En cuanto al estado deshabilitado, el atributo disabled está disponible para el elemento <button> , así como para todos los elementos del formulario, incluido <fieldset> . En serio. ¿Sabía que puede deshabilitar un montón de entradas agrupadas simplemente aplicando un solo atributo al <fieldset> ?

Un grupo de entradas deshabilitadas y un botón.
Un montón de entradas deshabilitadas con un solo atributo (vista previa grande)
 <fieldset disabled> <legend>A bunch of numb inputs</legend> <p> <label> <input type="radio" name="option"> Of course it's a link </label> </p> <p> <label> <input type="radio" name="option"> Obviously, it's a button </label> </p> <p> <label> <input type="radio" name="option"> I just wanna go home </label> </p> <button type="button">Button</button> </fieldset>

¡Ahora lo sabes! Este atributo no solo deshabilita todos los eventos en los elementos del formulario, sino que también los elimina del orden de tabulación. ¡Problema resuelto!

 <button disabled type="button" class="button"> Something </button>

¡Pero espera hay mas! También activa la pseudoclase :disabled en CSS, lo que significa que podemos deshacernos del modificador BEM para declarar estilos y usar el modificador dinámico integrado en su lugar.

 .button:disabled { background-color: #9B9B9B; }

En cuanto a los estilos feos del navegador, no tenemos que usar todo Normalize.css para arreglar un solo botón. Úselo como una fuente de sabiduría: las tres líneas adicionales a continuación solucionarán la mayoría de las molestas diferencias con el <div> . Si alguna vez necesita más, puede copiar las partes relevantes de él.

 .button { font-size: 100%; font-family: inherit; border: none; }

Hecho. ¡HTML no es tan malo después de todo!

Pero si te sorprende de vez en cuando, asegúrate de consultar la especificación HTML para obtener respuestas. Se ha vuelto mucho más amigable con los años y está lleno de buenos ejemplos de uso y accesibilidad. Y, por supuesto, el bueno de HTML5 Doctor sigue siendo un lugar confiable para descubrir la diferencia entre los elementos <section> y <article> y para verificar si el esquema del documento es una cosa todavía (no realmente). Es muy probable que también termines leyendo la documentación HTML de Mozilla, y tampoco te arrepentirás.

¡Esta tarea ya está hecha! ¿Que sigue? ¿Un calendario de carrusel desplegable con un campo de búsqueda? ¡Oh mi! Buena suerte con eso. Pero recuerda: ¡el <button> es tu amigo!

Lectura adicional en SmashingMag:

  • Cómo diseñar mejores botones
  • Creación de botones de alternancia inclusivos
  • Diseño de botón fantasma: ¿es esto realmente todavía una cosa (y por qué)?
  • Patrones de diseño: cuando romper las reglas está bien