Krypton Solid

Cómo mejorar las ventanas modales para todos

Cómo mejorar las ventanas modales para todos

Para usted, las ventanas modales pueden ser una bendición de espacio adicional en la pantalla, proporcionando una forma de entregar información contextual, notificaciones y otras acciones relevantes para la pantalla actual. Por otro lado, los modales pueden parecer un truco que te has visto obligado a cometer para meter contenido adicional en la pantalla. Estos son los extremos del espectro y los usuarios están atrapados en el medio. Dependiendo de cómo un usuario navegue por Internet, las ventanas modales pueden ser francamente confusas.

Los modales cambian rápidamente el enfoque visual de una parte de un sitio web o aplicación a otra área de contenido (con suerte relacionado). La acción generalmente no es discordante si la inicia el usuario, pero puede ser molesta y desorientadora si ocurre automáticamente, como sucede con los primos malvados de la ventana modal, la «pantalla de la queja» y el «intersticial».

Otras lecturas en SmashingMag:

Sin embargo, los modales son simplemente una leve molestia al final, ¿verdad? El usuario solo tiene que hacer clic en el botón «cerrar», hojear rápidamente algún contenido o completar un formulario para descartarlo.

Bueno, imagina que tuvieras que navegar por la web con un teclado. Suponga que aparece una ventana modal en la pantalla y tiene muy poco contexto para saber qué es y por qué oculta el contenido que está intentando explorar. Ahora te estás preguntando: «¿Cómo interactúo con esto?» o «¿Cómo me deshago de él?» porque el foco de su teclado no se ha movido automáticamente a la ventana modal.

Este escenario es más común de lo que debería ser. Y es bastante fácil de resolver, siempre que hagamos que nuestro contenido sea accesible para todos a través de prácticas sólidas de usabilidad.

Por ejemplo, configuré un demostración de una ventana modal inaccesible que aparece en la carga de la página y que no es del todo semántico. Primero, interactúe con él usando su mouse para ver que realmente funciona. Luego, intente interactuar con él usando solo su teclado.

Una mejor semántica conduce a una mejor usabilidad y accesibilidad

Muchas ventanas modales carecen de usabilidad y accesibilidad. Ya sea que se utilicen para proporcionar acciones o entradas adicionales para la interacción con la página, para incluir más información sobre una sección particular de contenido o para proporcionar notificaciones que se puedan descartar fácilmente, los modales deben ser fáciles de usar para todos.

Para lograr este objetivo, primero debemos centrarnos en la semántica del marcado modal. Esto puede parecer una obviedad, pero no siempre se sigue el paso.

Supongamos que un sitio web de juegos popular tiene una superposición modal de página completa y ha implementado un botón «cerrar» con el siguiente código:


<div id="modal_overlay">
  <div id="modal_close" onClick="modalClose()">
    X
  </div>
  …
</div>

Esto div elemento no tiene un significado semántico detrás de él. Los visitantes videntes sabrán que este es un botón de «cerrar» porque parece uno. Tiene un estado de desplazamiento, por lo que hay alguna indicación visual de que se puede interactuar con él.

Pero este elemento no tiene un significado semántico heredado para las personas que usan un teclado o un lector de pantalla.

No hay una forma predeterminada de permitir a los usuarios tabular a un div sin agregar un tabindex atribuirle. Sin embargo, también necesitaríamos agregar un :focus estado para indicar visualmente que es el elemento activo. Eso todavía no les da a los lectores de pantalla suficiente información para que los usuarios puedan discernir el significado del elemento. Una «X» es la única etiqueta aquí. Si bien podemos suponer que las personas que usan lectores de pantalla sabrían que la letra «X» significa «cerca», si fuera un signo de multiplicación (utilizando la entidad HTML &times;) o una cruz (), algunos lectores de pantalla no lo leerían en absoluto. Necesitamos una mejor alternativa.

Podemos eludir todos estos problemas simplemente escribiendo el marcado semántico correcto para un botón y agregando una etiqueta ARIA para lectores de pantalla:


<div id="modal_overlay">
  <button type="button" class="btn-close" id="modal_close" aria-label="close">
    X
  </button>
</div>

Cambiando el div a un botón, hemos mejorado significativamente la semántica de nuestro botón «cerrar». Hemos abordado la expectativa común de que el botón se puede tabular con un teclado y parecer enfocado, y hemos proporcionado contexto agregando la etiqueta ARIA para lectores de pantalla.

Ese es solo un ejemplo de cómo hacer que el marcado de nuestros modales sea más semántico, pero podemos hacer mucho más para crear una experiencia útil y accesible.

Haciendo que los modales sean más utilizables y accesibles

El marcado semántico contribuye en gran medida a la creación de una ventana modal totalmente utilizable y accesible, pero aún más CSS y JavaScript pueden llevar la experiencia al siguiente nivel.

Incluidos los estados de enfoque

¡Proporcione un estado de enfoque! Obviamente, esto no es exclusivo de las ventanas modales; muchos elementos carecen de un estado de enfoque adecuado de una forma u otra más allá del predeterminado básico del navegador (que puede o no haber sido borrado por su restablecimiento de CSS). Como mínimo, empareje el estado de enfoque con el estado de desplazamiento que ya ha diseñado:


.btn:hover, .btn:focus {
  background: #f00;
}

Sin embargo, debido a que enfocar y desplazarse son diferentes tipos de interacción, darle al estado de enfoque su propio estilo tiene sentido.


.btn:hover {
  background: #f00;
}

:focus {
  box-shadow: 0 0 3px rgba(0,0,0,.75);
}

Realmente, cualquier elemento que pueda enfocarse debe tener un estado de enfoque. Tenga esto en cuenta si está ampliando el contorno de puntos predeterminado del navegador.

Guardar último elemento activo

Cuando se carga una ventana modal, se debe guardar el elemento con el que el usuario interactuó por última vez. De esa forma, cuando la ventana modal se cierre y el usuario regrese a donde estaba, se habrá mantenido el foco en ese elemento. Piense en ello como un marcador. Sin él, cuando el usuario cierra el modal, sería enviado de regreso al principio del documento, a la izquierda para encontrar su lugar. Agregue lo siguiente a las funciones de apertura y cierre de su modal para guardar y volver a habilitar el enfoque del usuario.


var lastFocus;

function modalShow () {
  lastFocus = document.activeElement;
}

function modalClose () {
  lastFocus.focus(); // place focus on the saved element
}

Enfoque cambiante

Cuando se carga el modal, el foco debe cambiar del último elemento activo a la ventana modal en sí o al primer elemento interactivo en el modal, como un elemento de entrada. Esto hará que el modal sea más utilizable porque los visitantes videntes no tendrán que alcanzar el mouse para hacer clic en el primer elemento, y los usuarios del teclado no tendrán que pasar por un montón de elementos DOM para llegar allí.


var modal = document.getElementById('your-modal-id-here');

function modalShow () {
   modal.setAttribute('tabindex', '0');
   modal.focus();
}

Ir a pantalla completa

Si su modal ocupa la pantalla completa, oculte el contenido del documento principal tanto para los usuarios videntes como para los usuarios de lectores de pantalla. Sin que esto suceda, un usuario de teclado podría fácilmente salir del modal sin darse cuenta, lo que podría llevarlo a interactuar con el documento principal antes de completar lo que sea que la ventana modal le esté pidiendo que haga.

Utilice el siguiente JavaScript para limitar el enfoque del usuario a la ventana modal hasta que se descarte:


function focusRestrict ( event ) {
  document.addEventListener('focus', function( event ) {
    if ( modalOpen && !modal.contains( event.target ) ) {
      event.stopPropagation();
      modal.focus();
    }
  }, true);
}

Si bien queremos evitar que los usuarios pasen por el resto del documento mientras un modal está abierto, no queremos evitar que accedan al Chrome del navegador (después de todo, los usuarios videntes no esperarían estar atrapados en la pestaña del navegador mientras una ventana modal está abierta). El JavaScript anterior evita tabular el contenido del documento fuera de la ventana modal, en lugar de llevar al usuario a la parte superior del modal.

Si también ponemos el modal en la parte superior del árbol DOM, como primer hijo de body, luego golpeando Mayús + Tabulador sacaría al usuario del modal y lo llevaría al Chrome del navegador. Si no puede cambiar la ubicación del modal en el árbol DOM, utilice el siguiente JavaScript en su lugar:


var m = document.getElementById('modal_window'),
    p = document.getElementById('page');

// Remember that <div id="page"> surrounds the whole document,
// so aria-hidden="true" can be applied to it when the modal opens.

function swap () {
  p.parentNode.insertBefore(m, p);
}

swap();

Si no puede mover el modal en el árbol DOM o reposicionarlo con JavaScript, aún tiene otras opciones para limitar el enfoque al modal. Puede realizar un seguimiento del primer y último elemento enfocable en la ventana modal. Cuando el usuario llega al último y pulsa Pestaña, puede cambiar el enfoque de nuevo a la parte superior del modal. (Y harías lo contrario por Mayús + Tabulador.)

Una segunda opción sería crear una lista de todos los nodos enfocables en la ventana modal y, tras la activación modal, permitir la tabulación solo a través de esos nodos.

Una tercera opción sería encontrar todos los nodos enfocables fuera del modal y establecer tabindex=“-1” en ellos.

El problema con estas primeras y segundas opciones es que hacen inaccesible el Chrome del navegador. Si debe tomar esta ruta, agregue un botón «cerrar» bien marcado al modal y apoye el Escapar las claves son críticas; sin ellos, atraparás efectivamente a los usuarios del teclado en el sitio web.

La tercera opción permite tabular dentro del modal y el cromo del navegador, pero tiene el costo de rendimiento de enumerar todos los elementos enfocables en la página y anular su capacidad para concentrarse. Puede que el costo no sea mucho en una página pequeña, pero en una página con muchos enlaces y elementos de formulario, puede convertirse en una tarea ardua. Sin mencionar que cuando el modal se cierra, deberá devolver todos los elementos a su estado anterior.

Claramente, tenemos mucho que considerar para permitir a los usuarios tabular de manera efectiva dentro de un modal.

Despedir

Finalmente, los modales deberían ser fáciles de descartar. Estándar alert() Los diálogos modales se pueden cerrar presionando el botón Escapar clave, por lo que se esperaría seguir su ejemplo con nuestro modal, y una conveniencia. Si su modal tiene múltiples elementos enfocables, permitiendo al usuario simplemente presionar Escapar es mucho mejor que obligarlos a desplazarse por el contenido para llegar al botón «cerrar».


function modalClose ( e ) {
  if ( !e.keyCode || e.keyCode === 27 ) {
    // code to close modal goes here
  }
}

document.addEventListener('keydown', modalClose);

Además, cerrar un modal de pantalla completa cuando se hace clic en la superposición es convencional. La excepción es si no desea cerrar el modal hasta que el usuario haya realizado una acción.

Utilice el siguiente JavaScript para cerrar el modal cuando el usuario haga clic en la superposición:


mOverlay.addEventListener('click', function( e )
  if (e.target == modal.parentNode)
    modalClose( e );
  }
}, false);

Pasos adicionales de accesibilidad

Más allá de los pasos de usabilidad descritos anteriormente, Funciones, estados y propiedades de ARIA agregará aún más ganchos para tecnologías de asistencia. Para algunos de estos, no se requiere nada más que agregar el atributo correspondiente a su marcado; para otros, se requiere JavaScript adicional para controlar el estado de un elemento.

aria oculta

Utilizar el aria-hidden atributo. Al alternar el valor true y false, el elemento y cualquiera de sus elementos secundarios estarán ocultos o visibles para los lectores de pantalla. Sin embargo, al igual que con todos los atributos de ARIA, no tiene un estilo predeterminado y, por lo tanto, no se ocultará a los usuarios videntes. Para ocultarlo, agregue el siguiente CSS:


.modal-window[aria-hidden=”true”] {
  display: none;
}

Tenga en cuenta que el selector es bastante específico aquí. La razón es que es posible que no queramos todos los elementos con aria-hidden=“true” ocultarse (como en nuestro ejemplo anterior de la «X» para el botón «cerrar»).

role = «diálogo»

Agregar role=“dialog” al elemento que contiene el contenido del modal. Esto le dice a las tecnologías de asistencia que el contenido requiere la respuesta o confirmación del usuario. Nuevamente, combine esto con JavaScript que cambia el enfoque del último elemento activo en el documento al modal o al primer elemento enfocable en el modal.

Sin embargo, si el modal es más un mensaje de error o alerta que requiere que el usuario ingrese algo antes de continuar, entonces use role=“alertdialog” en lugar de. Nuevamente, establezca el foco en él automáticamente con JavaScript y limítelo al modal hasta que se tome una acción.

etiqueta-aria

Utilizar el aria-label o aria-labelledby atributo junto con role=“dialog”. Si su ventana modal tiene un encabezado, puede usar el aria-labelledby atributo para señalarlo haciendo referencia al ID del encabezado. Si su modal no tiene un encabezado por alguna razón, entonces al menos puede usar el aria-label para proporcionar una etiqueta concisa sobre el elemento que los lectores de pantalla pueden analizar.

¿Qué pasa con el elemento de diálogo de HTML5?

Chrome 37 beta y Firefox Nightly 34.0a1 son compatibles con dialog elemento, que proporciona información adicional semántica y de accesibilidad para ventanas modales. Una vez que este nativo dialog elemento está establecido, no necesitaremos aplicar role=“dialog” a elementos que no son de diálogo. Por ahora, incluso si está utilizando un polyfill para el dialog elemento, también use role=“dialog” para que los lectores de pantalla sepan cómo manejar el elemento.

Lo emocionante de este elemento no es solo que cumple la función semántica de un diálogo, sino que viene con sus propios métodos, que reemplazarán el JavaScript y CSS que actualmente necesitamos escribir.

Por ejemplo, para mostrar o descartar un diálogo, escribiríamos esta base de JavaScript:


var modal = document.getElementById('myModal'),
  openModal = document.getElementById('btnOpen'),
  closeModal = document.getElementById('btnClose');

// to show our modal
openModal.addEventListener( 'click', function( e ) {
  modal.show();
  // or
  modal.showModal();
});

// to close our modal
closeModal.addEventListener( 'click', function( e ) {
  modal.close();
});

La show() El método abre el cuadro de diálogo y, al mismo tiempo, permite a los usuarios interactuar con otros elementos de la página. La showModal() El método inicia el diálogo y evita que los usuarios interactúen con cualquier cosa que no sea el modal mientras está abierto.

La dialog elemento también tiene el open propiedad, establecida en true o false, que reemplaza aria-hidden. Y tiene lo suyo ::backdrop pseudo-elemento, que nos permite diseñar el modal cuando se abre con el showModal() método.

Hay más que aprender sobre el dialog elemento de lo que se menciona aquí. Puede que no esté listo para el horario de máxima audiencia, pero una vez que lo esté, este elemento semántico contribuirá en gran medida a ayudarnos a desarrollar experiencias utilizables y accesibles.

¿A dónde ir desde aquí?

Ya sea que use un complemento de jQuery o una solución de cosecha propia, retroceda y evalúe la usabilidad y accesibilidad general de su modal. Por menores que sean los modales para la web en general, son lo suficientemente comunes como para que si todos intentáramos hacerlos más amigables y accesibles, haríamos de la web un lugar mejor.

He preparado un demostración de una ventana modal que implementa todas las funciones de accesibilidad cubiertas en este artículo.

Deja un comentario