Cómo crear la navegación principal para un sitio web

En este tutorial se describe cómo crear una navegación principal accesible de un sitio web. Aprenderás sobre HTML semántico, accesibilidad y cómo el uso de atributos ARIA a veces puede ser más perjudicial que beneficioso.

Manuel Matuzović
Manuel Matuzović

Hay muchas formas diferentes de crear la navegación principal de un sitio web en términos de estilo, funcionalidad y el lenguaje de marcado y la información semántica subyacente. Si la implementación es demasiado minimalista, funciona para la mayoría de las personas, pero la experiencia del usuario (UX) podría no ser buena. Si está sobrecargado, podría confundir a los usuarios o incluso impedir que puedan acceder a él.

Para la mayoría de los sitios web, lo mejor es crear algo que no sea ni demasiado simple ni demasiado complicado.

Compilación capa por capa

En este tutorial se comienza con una configuración básica y se agregan funciones capa por capa hasta el punto en el que proporcionas la información, el estilo y la funcionalidad suficientes para complacer a la mayoría de los usuarios. Para lograrlo, usa el principio de mejora progresiva, que establece que debes comenzar con la solución más fundamental y sólida y agregar capas de funcionalidad de manera progresiva. Si una capa no funciona por algún motivo, la navegación seguirá funcionando porque regresa a la capa subyacente de manera elegante.

Estructura básica

Para una navegación básica, necesitas dos elementos: elementos <a> y algunas líneas de CSS para mejorar el estilo predeterminado de tus vínculos.

<a href="/home">Home</a>
<a href="/about-us">About us</a>
<a href="/pricing">Pricing</a>
<a href="/contact">Contact</a>
/* Define variables for your colors */
:root {
  --color-shades-dark: rgb(25, 25, 25);
}

/* Use the alternative box model
Details: <https://web.dev/learn/css/box-model/> */
*{
  box-sizing: border-box;
}

/* Basic font styling */
body {
  font-family: Segoe UI, system-ui, -apple-system, sans-serif;
  font-size: 1.6rem;
}

/* Link styling */
a {
  --text-color: var(--color-shades-dark);
  border-block-end: 3px solid var(--border-color, transparent);
  color: var(--text-color);
  display: inline-block;
  margin-block-end: 0.5rem; /* See note at the bottom of this chapter */
  margin-inline-end: 0.5rem;
  padding: 0.1rem;
  text-decoration: none;
}

/* Change the border-color on :hover and :focus */
a:where(:hover, :focus) {
  --border-color: var(--text-color);
}
Consulta el Paso 1: HTML básico y CSS" en CodePen.

Esto funciona bien para la mayoría de los usuarios, independientemente de cómo accedan al sitio. Se puede acceder a la navegación con un mouse, un teclado, un dispositivo táctil o un lector de pantalla, pero se podrían mejorar. Puedes mejorar la experiencia extendiendo este patrón básico con información e información adicional.

Puede hacer lo siguiente:

  • Destaca la página activa.
  • Anuncia la cantidad de elementos a los usuarios de lectores de pantalla.
  • Agrega un punto de referencia y permite que los usuarios de lectores de pantalla accedan a la navegación directamente con un acceso directo.
  • Ocultar la navegación en viewports estrechos
  • Mejora el estilo de enfoque.

Destacar la página activa

Para destacar la página activa, puedes agregar una clase al vínculo correspondiente.

<a href="/about-us" class="active-page">About us</a>

El problema con este enfoque es que transmite la información cuyo vínculo está activo de forma puramente visual. Un usuario de un lector de pantalla ciego no podía distinguir entre la página activa y las demás. Afortunadamente, el estándar de Aplicaciones de Internet Enriquecidas Accesibles (ARIA) también ofrece una manera de comunicar esta información de manera semántica. Usa el atributo y el valor aria-current="page" en lugar de una clase.

aria-current (estado) indica el elemento que representa el elemento actual dentro de un contenedor o un conjunto de elementos relacionados. Un token de página que se usa para indicar un vínculo dentro de un conjunto de vínculos de paginación, en el que el vínculo tiene un estilo visual para representar la página que se muestra. [Aplicaciones de Internet enriquecidas accesibles (WAI-ARIA) 1.1](https://www.w3.org/TR/wai-aria/#aria-current)

Con el atributo adicional, un lector de pantalla ahora anuncia algo como "página actual, vínculo, Acerca de nosotros" en lugar de solo "vínculo, Acerca de nosotros".

<a href="/about-us" aria-current="page" class="active-page">About us</a>

Un efecto secundario conveniente es que puedes usar el atributo para seleccionar el vínculo activo en CSS, lo que hará que la clase active-page quede obsoleta.

<a href="/home">Home</a>
<a href="/about-us" aria-current="page">About us</a>
<a href="/pricing">Pricing</a>
<a href="/contact">Contact</a>
/* Change border-color and color for the active page */
[aria-current="page"] {
  --border-color: var(--color-highlight);
  --text-color: var(--color-highlight);
}
Mira el Paso 2: Destaca la página activa en CodePen.

Anunciar la cantidad de elementos

Al observar la navegación, los usuarios videntes pueden darse cuenta de que solo contiene cuatro enlaces. Un usuario ciego de pantalla no puede obtener esta información con tanta rapidez. Es posible que deban consultar toda la lista de vínculos. Es posible que esto no sea un problema si la lista es corta, como en este ejemplo, pero si contiene 40 vínculos, esta tarea puede ser engorrosa. Si el usuario de un lector de pantalla sabe de antemano que la navegación contiene muchos vínculos, es posible que decida usar una forma de navegación diferente y más eficiente, como la búsqueda en el sitio.
Una buena forma de comunicar la cantidad de elementos por adelantado es unir cada vínculo en un elemento de lista (<li>), anidado en una lista sin ordenar (<ul>).

<ul>
  <li>
     <a href="/home">Home</a>
  </li>
  <li>
    <a href="/about-us" aria-current="page">About us</a>
  </li>
  <li>
    <a href="/pricing">Pricing</a>
  </li>
  <li>
    <a href="/contact">Contact</a>
  </li>
</ul>

Cuando el usuario de un lector de pantalla encuentre la lista, su software anunciará algo como "lista, 4 elementos".

A continuación, te presentamos una demostración de la navegación que se usa con el lector de pantalla NVDA en Windows.

Ahora, debes adaptar el diseño para que se vea como antes.

/* Remove the default list styling and create a flexible layout for the list */
ul {
  display: flex;
  flex-wrap: wrap;
  gap: 1rem;
  list-style: none;
  margin: 0;
  padding: 0;
}

/* Basic link styling */
a {
  --text-color: var(--color-shades-dark);

  border-block-end: 3px solid var(--border-color, transparent);
  color: var(--text-color);
  padding: 0.1rem;
  text-decoration: none;
}

El uso de listas puede presentar muchas ventajas para los usuarios de lectores de pantalla:

  • Puede obtener la cantidad total de elementos antes de interactuar con ellos.
  • Pueden usar combinaciones de teclas para pasar de un elemento a otro.
  • Pueden usar combinaciones de teclas para pasar de una lista a otra.
  • El lector de pantalla podría anunciar el índice del elemento actual (por ejemplo, "elemento de la lista, dos de cuatro").

Además, si la página se presenta sin CSS, la lista muestra los vínculos como un grupo coherente de elementos, en lugar de solo una pila.

Un detalle notable sobre VoiceOver en Safari es que pierdes todas estas ventajas cuando configuras list-style: none. Se diseñó de este modo. El equipo de WebKit decidió quitar la semántica de las listas cuando una lista no parece ser una lista. Según la complejidad de tu navegación, puede o no ser un problema. Por un lado, la navegación aún se puede usar y solo afecta a VoiceOver en Safari. VoiceOver con Chrome o Firefox sigue anunciando la cantidad de elementos, además de otros lectores de pantalla, como NVDA. Por otro lado, la información semántica podría ser realmente útil en algunas situaciones. Para tomar esa decisión, debes probar la navegación con usuarios reales de lectores de pantalla y obtener sus comentarios. Si decides que necesitas que VoiceOver en Safari se comporte como todos los demás lectores de pantalla, puedes solucionar el problema configurando de forma explícita el rol de lista de ARIA en <ul>. Esto revierte el comportamiento al estado anterior a que hayas quitado el diseño de lista. Visualmente, la lista sigue siendo la misma.

<ul role="list">
  <li>
     <a href="/home">Home</a>
  </li>
  ...
</ul>
Consulta el Paso 3: Anunciar la cantidad de elementos en CodePen.

Agregar un punto de referencia

Con poco esfuerzo, has realizado grandes mejoras para los usuarios de lectores de pantalla, pero hay una cosa más que puedes hacer. La navegación sigue siendo, en términos semánticos, solo una lista de vínculos y es difícil saber que esta lista específica es la navegación principal de tu sitio web. Para convertir esta lista común en una lista de navegación, une el <ul> en un elemento <nav>.

Usar el elemento <nav> tiene varias ventajas. En particular, un lector de pantalla anuncia algo como "navegación" cuando el usuario interactúa con él y agrega un punto de referencia a la página. Los puntos de referencia son regiones especiales de la página, como <header>, <footer> o <main>, a las que puede saltar un lector de pantalla. Tener puntos de referencia en una página puede ser útil, ya que les permite a los usuarios de lectores de pantalla acceder a regiones importantes de la página directamente sin tener que interactuar con el resto de la página. Por ejemplo, para pasar de un punto de referencia a otro, presiona la tecla D en NVDA. En Voice Over, puedes usar el rotor para enumerar todos los puntos de referencia en la página presionando VO + U.

Una lista de cuatro puntos de referencia: banner, navegación, principal y información de contenido.
Rotor en VoiceOver enumera todos los puntos de referencia en una página.

En esta lista, verás 4 puntos de referencia: banner, que es el elemento <header>, navigation es el <nav>, main el elemento <main>, y la información de contenido es el <footer>. Esta lista no debería ser demasiado larga. En realidad, solo debes marcar partes críticas de tu IU como puntos de referencia, como la búsqueda en el sitio, una navegación local o una paginación.

Si tienes una navegación para todo el sitio, una navegación local para la página y una paginación en una sola página, es posible que también tengas 3 elementos <nav>. Está bien, pero ahora hay tres puntos de referencia de navegación y, semánticamente, todos se ven iguales. Es difícil diferenciarlos, a menos que conozcas muy bien la estructura de la página.

Imagen en la que se muestran tres puntos de referencia que dicen &quot;navegación&quot;.
El rotor de VoiceOver enumera tres puntos de referencia de navegación sin etiquetar.

Para que se distingan, debes etiquetarlos usando aria-labelledby o aria-label.

<nav aria-label="Main">
    <ul>
      <li>
         <a href="/home">Home</a>
      </li>
      ...
  </ul>
</nav>
...
<nav aria-label="Select page">
    <ul>
      <li>
         <a href="/page-1">1</a>
      </li>
      ...
    </ul>
</nav>

Si la etiqueta que elegiste ya existe en alguna parte de la página, puedes usar aria-labelledby en su lugar y hacer referencia a la etiqueta existente con el atributo id.

<nav aria-labelledby="pagination_heading">
  <h2 id="pagination_heading">Select a page</h2>
  <ul>
    <li>
       <a href="/page-1">1</a>
    </li>
    ...
  </ul>
</nav>

Una etiqueta concisa es suficiente, no uses demasiado. Omite expresiones como "navegación" o "menú" porque el lector de pantalla ya proporciona esta información a los usuarios.

Puntos de referencia
VoiceOver enumera los puntos de referencia "banner", "navegación principal", "principal", "navegación de página", "selección de navegación de la página" e "información de contenido".
Consulta el Paso 4: Cómo agregar un punto de referencia en CodePen.

Ocultar la navegación en viewports estrechos

En lo personal, no me gusta mucho ocultar la navegación principal en viewports estrechos, pero si la lista de vínculos se vuelve demasiado larga, no hay forma de evitarla. Si ese es el caso, en lugar de la lista, los usuarios ven un botón con la etiqueta “Menú” o un ícono de hamburguesa o una combinación. Si haces clic en el botón, se muestra y se oculta la lista. Si conoces los conceptos básicos de JavaScript y CSS, es una tarea viable, pero debes prestar atención a varios aspectos en términos de UX y accesibilidad.

  • Debes ocultar la lista de un modo accesible.
  • El teclado debe poder acceder a la navegación.
  • La navegación debe comunicar si es visible o no.

Cómo agregar un botón de hamburguesa

Dado que estás siguiendo el principio de mejora progresiva, debes asegurarte de que tu navegación siga funcionando y tenga sentido incluso con JavaScript desactivado.
Lo primero que tu navegación necesita es un botón de hamburguesa. Puedes crearlo en HTML en un elemento de plantilla, clonarlo en JavaScript y agregarlo al panel de navegación.

Una página en la que se muestra un botón de hamburguesa.
Resultado: En lugar de vínculos, la navegación muestra un botón de hamburguesa en viewports estrechos.
<nav id="mainnav">
  ...
</nav>

<template id="burger-template">
  <button type="button" aria-expanded="false" aria-label="Menu" aria-controls="mainnav">
    <svg width="24" height="24" aria-hidden="true">
      <path d="M3 18h18v-2H3v2zm0-5h18v-2H3v2zm0-7v2h18V6H3z">
    </svg>
  </button>
</template>
  1. El atributo aria-expanded le indica al software del lector de pantalla si se expandió o no el elemento que controla el botón.
  2. aria-label le asigna al botón un nombre de accesibilidad, una alternativa de texto para el ícono de hamburguesa.
  3. Puedes ocultar el elemento <svg> de la tecnología de accesibilidad mediante el uso de aria-hidden porque ya tiene una etiqueta de texto proporcionada por aria-label.
  4. aria-controls le indica a la tecnología de accesibilidad, que admite el atributo (por ejemplo, JAWS), qué elemento controla el botón.
const nav = document.querySelector('#mainnav')
const list = nav.querySelector('ul');
const burgerClone = document.querySelector('#burger-template').content.cloneNode(true);
const button = burgerClone.querySelector('button');

// Toggle aria-expanded attribute
button.addEventListener('click', e => {
  // aria-expanded="true" signals that the menu is currently open
  const isOpen = button.getAttribute('aria-expanded') === "true"
  button.setAttribute('aria-expanded', !isOpen);
});

// Hide list on keydown Escape
nav.addEventListener('keyup', e => {
  if (e.code === 'Escape') {
    button.setAttribute('aria-expanded', false);
  }
});

// Add the button to the page
nav.insertBefore(burgerClone, list);
  1. Es conveniente que los usuarios puedan cerrar la navegación cuando lo deseen, por ejemplo, presionando la tecla Escape.
  2. Es importante usar insertBefore en lugar de appendChild porque el botón debe ser el primer elemento de tu navegación. Si el usuario de un teclado o un lector de pantalla presiona Tab después de hacer clic en el botón, espera enfocar el primer elemento de la lista. Si el botón aparece después de la lista, no sería así.

A continuación, restablece el estilo predeterminado del botón y asegúrate de que solo sea visible en viewports estrechos.

@media (min-width: 48em) {
  nav {
    --nav-button-display: none;
  }
}

/* Reset button styling */
button {
  all: unset;
  display: var(--nav-button-display, flex);
}
Consulta el Paso 5: Agrega un botón de hamburguesa en CodePen.

Ocultando la lista

Antes de ocultar la lista, posiciona y aplica el estilo de la navegación y la lista de modo que el diseño se optimice para viewports estrechos, pero se vea bien en pantallas más grandes.
Primero, quita la <nav> del flujo natural de la página y colócala en la esquina superior del viewport.

@media (min-width: 48em) {
  nav {
    --nav-button-display: none;
    --nav-position: static;
  }
}

nav {
  position: var(--nav-position, fixed);
  inset-block-start: 1rem;
  inset-inline-end: 1rem;
}

A continuación, cambia el diseño en viewports estrechos agregando una nueva propiedad personalizada (—-nav-list-layout). El diseño es de columnas de forma predeterminada y cambia a filas en pantallas más grandes.

@media (min-width: 48em) {
  nav {
    --nav-button-display: none;
    --nav-position: static;
  }

  ul {
    --nav-list-layout: row;
  }
}

ul {
  display: flex;
  flex-direction: var(--nav-list-layout, column);
  flex-wrap: wrap;
  gap: 1rem;
  list-style: none;
  margin: 0;
  padding: 0;
}

Tu navegación debería verse así en viewports estrechos.

La página muestra la lista de navegación y el botón de hamburguesa.
El botón de hamburguesa y la lista se colocan en la esquina superior del viewport.

Es obvio que la lista necesita algo de CSS. Lo moveremos hacia arriba hasta la esquina superior, haremos que llene toda la pantalla de forma vertical y aplicaremos un background-color y un box-shadow.

@media (min-width: 48em) {
  nav {
    --nav-button-display: none;
    --nav-position: static;
  }
  
  ul {
    --nav-list-layout: row;
    --nav-list-position: static;
    --nav-list-padding: 0;
    --nav-list-height: auto;
    --nav-list-width: 100%;
    --nav-list-shadow: none;
  }
}

ul {
  background: rgb(255, 255, 255);
  box-shadow: var(--nav-list-shadow, -5px 0 11px 0 rgb(0 0 0 / 0.2));
  display: flex;
  flex-direction: var(--nav-list-layout, column);
  flex-wrap: wrap;
  gap: 1rem;
  height: var(--nav-list-height, 100vh);
  list-style: none;
  margin: 0;
  padding: var(--nav-list-padding, 2rem);
  position: var(--nav-list-position, fixed);
  inset-block-start: 0; /* Logical property. Equivalent to top: 0; */
  inset-inline-end: 0; /* Logical property. Equivalent to right: 0; */
  width: var(--nav-list-width, min(22rem, 100vw));
}

button {
  all: unset;
  display: var(--nav-button-display, flex);
  position: relative;
  z-index: 1;
}

La lista debería verse así en viewports estrechos, más como una barra lateral que una lista simple.

Se abre la lista de navegación.

Por último, oculta la lista, muéstrala solo cuando el usuario haga clic en el botón una vez y ocúltala cuando vuelva a hacer clic. Es importante ocultar solo la lista y no toda la navegación, ya que ocultarla también implicaría ocultar un punto de referencia importante.

Anteriormente, agregaste un evento de clic al botón para activar o desactivar el valor del atributo aria-expanded. Puedes usar esa información como condición para mostrar y ocultar la lista en CSS.

@media (min-width: 48em) {
  ul {
    --nav-list-visibility: visible;
  }
}

ul {
  visibility: var(--nav-list-visibility, visible);
}

/* Hide the list on narrow viewports, if it comes after an element with
   aria-expanded set to "false". */
[aria-expanded="false"] + ul {
  visibility: var(--nav-list-visibility, hidden);
}

Es importante usar una declaración de propiedad como visibility: hidden o display: none, en lugar de opacity: 0 o translateX(100%), para ocultar la lista. Estas propiedades garantizan que los vínculos no sean enfocables cuando la navegación está oculta. Si usas opacity o translate, se quitará el contenido visualmente, por lo que los vínculos serán invisibles, pero se podría acceder a ellos con el teclado, lo que resultaría confuso y frustrante. Si usas visibility o display, se oculta visualmente y se vuelve inaccesible, por lo que se oculta para todos los usuarios.

Consulta el Paso 6: Oculta la lista.

Cómo animar la lista

Si te preguntas por qué usar visibility: hidden; en lugar de display: none;, es porque puedes animar la visibilidad. Solo tiene dos estados, hidden y visible, pero puedes combinarlo con otra propiedad, como transform o opacity, para crear un efecto de deslizamiento o de fundido de entrada. Eso no funcionaría con Display: none porque la propiedad de Display no se puede animar.

La siguiente CSS realiza la transición opacity para crear un efecto de fundido de entrada y de salida.

ul {
  transition: opacity 0.6s linear, visibility 0.3s linear;
  visibility: var(--nav-list-visibility, visible);
}

[aria-expanded="false"] + ul {
  opacity: 0;
  visibility: var(--nav-list-visibility, hidden);
}

En cambio, si deseas animar el movimiento, deberías considerar unir la propiedad transition en una consulta de medios prefers-reduced-motion, ya que las animaciones pueden provocar náuseas, mareos y dolores de cabeza en algunos usuarios.

ul {
  visibility: var(--nav-list-visibility, visible);
}

@media (prefers-reduced-motion: no-preference) {
  ul {
    transition: transform 0.6s cubic-bezier(.68,-0.55,.27,1.55), visibility 0.3s linear;
  }
}

[aria-expanded="false"] + ul {
  transform: var(--nav-list-transform, translateX(100%));
  visibility: var(--nav-list-visibility, hidden);
}

Esto garantiza que solo las personas que no tengan preferencia por el movimiento reducido vean la animación.

Consulta el Paso 7: Anima la lista en CodePen.

Mejora el estilo de enfoque

Los usuarios de teclado dependen de los estilos de enfoque de los elementos para la orientación y la navegación en una página. Los estilos de enfoque predeterminados son mejores que ninguno (lo que sucede si configuras outline: none), pero tener estilos de enfoque personalizados más claramente visibles mejora la experiencia del usuario.

Así se ven los estilos de enfoque predeterminados en el vínculo en Chrome 103.

Un contorno azul de 2 px alrededor de un vínculo enfocado en Chrome 103.

Puedes mejorar esto proporcionando tus propios estilos con tus propios colores. Si usas :focus-visible en lugar de :focus, permites que el navegador decida cuándo es apropiado mostrar los estilos de enfoque. Los estilos de :focus serán visibles para todos los usuarios, ya sean del mouse, del teclado y de la pantalla táctil, sin importar si los necesitan o no. Con :focus-visible, el navegador usa una heurística interna para decidir si mostrarlos solo a los usuarios del teclado o a todos.

/* Remove the default :focus outline */
*:focus {
  outline: none;
}

/* Show a custom outline on :focus-visible */
*:focus-visible {
  outline: 2px solid var(--color-shades-dark);
  outline-offset: 4px;
}

Navegadores compatibles con :focus-visible

Navegadores compatibles

  • 86
  • 86
  • 85
  • 15.4

Origen

Contorno oscuro de 2 px claramente visible con espaciado en el interior

Existen diferentes maneras de destacar elementos cuando están enfocados. Se recomienda usar la propiedad outline, ya que no interrumpe el diseño, lo que podría suceder con border, y funciona bien con el modo de contraste alto en Windows. Las propiedades que no funcionan bien son background-color o box-shadow, ya que es posible que no se muestren en absoluto con la configuración de contraste personalizada.

Un sitio con un fondo oscuro y el foco destacado en púrpura.
Ver Paso 8: Mejora los estilos de enfoque en CodePen.

¡Felicitaciones! Compilaste una navegación principal mejorada de forma progresiva, semánticamente enriquecida, accesible y optimizada para dispositivos móviles.

Siempre hay algo que se puede mejorar, por ejemplo:

  • Podrías considerar la opción de recuperar el enfoque dentro de la navegación o hacer que el resto de la página sea inerte en viewports estrechos.
  • Puedes agregar un vínculo para omitir en la parte superior de la página para permitir que los usuarios del teclado omitan la navegación.

Si recuerdan cómo comenzó este artículo, con el objetivo de que la solución "no sea demasiado simple ni demasiado complicada", ahí es donde estamos ahora. Sin embargo, es posible diseñar en exceso una navegación.

Hay una clara diferencia entre las navegaciones y los menús. Las navegaciones son colecciones de vínculos para navegar por documentos relacionados. Los menús son colecciones de acciones para realizar en un documento. A veces, estas tareas se superponen. Es posible que tengas una navegación que también incluya un botón que realice una acción, como abrir una ventana modal, o un menú en el que una acción navegue a otra página, como una página de ayuda. Cuando ese es el caso, es importante que no mezcles roles de ARIA, sino que identifiques el objetivo principal de tu componente y elijas el lenguaje de marcado y los roles según corresponda.

El elemento <nav> tiene un rol ARIA implícito de navegación, que es suficiente para comunicar que el elemento es una navegación, pero a menudo ves sitios que también usan el menú, la barra de menú y el elemento de menú. Como a veces usamos estos términos de forma indistinta, pensar que combinarlos para mejorar la experiencia de los usuarios de lectores de pantalla puede tener sentido. Antes de comprender por qué no suele ser el caso, veamos la definición oficial de estos roles.

El rol de navegación

Es una colección de elementos de navegación (generalmente vínculos) para navegar por el documento o los documentos relacionados.

navigation (rol) WAI-ARIA 1.1

El rol del menú

Un menú suele ser una lista de acciones o funciones comunes que el usuario puede invocar. El rol del menú es apropiado cuando se presenta una lista de elementos del menú de manera similar a un menú en una aplicación para computadoras.

menu (rol) WAI-ARIA 1.1

El rol de la barra de menú

Una presentación del menú que suele permanecer visible y que, por lo general, se presenta de forma horizontal. El rol de barra de menú se usa para crear una barra de menú similar a las que se encuentran en las aplicaciones de escritorio de Windows, Mac y Gnome. Una barra de menú se usa para crear un conjunto coherente de comandos de uso frecuente. Los autores deben asegurarse de que la interacción de la barra de menú sea similar a la interacción típica de la barra de menú en una interfaz gráfica de usuario de escritorio.

menubar (rol) WAI-ARIA 1.1

El rol menuitem

Es una opción en un conjunto de opciones contenido en un menú o una barra de menú.

menuitem (rol) WAI-ARIA 1.1

La especificación es muy clara aquí. Usa la navegación para navegar por el documento o los documentos relacionados y el menú solo para una lista de acciones o funciones similares a los menús en aplicaciones de escritorio. Si no estás compilando el siguiente documento de Google, es probable que no necesites ninguno de los roles de menú para la navegación principal.

¿Cuándo es apropiado un menú?

El uso principal de los elementos de menú no es la navegación, sino realizar acciones. Supongamos que tienes una lista o tabla de datos y que los usuarios pueden realizar determinadas acciones sobre cada elemento de la lista. Puedes agregar un botón a cada fila y mostrar las acciones cuando los usuarios hacen clic en el botón.

<ul>
  <li>
    Product 1

    <button aria-expanded="false" aria-controls="options1">Edit</button>

    <div role="menu" id="options1">
      <button role="menuitem">
        Duplicate
      </button>
      <button role="menuitem">
        Delete
      </button>
      <button role="menuitem">
        Disable
      </button>
    </div>
  </li>
  <li>
    Product 2
    ...
  </li>
</ul>

Implicaciones del uso de roles de menú

Es muy importante que uses estos roles de menú con prudencia, ya que muchas cosas pueden salir mal.

Los menús esperan una estructura del DOM determinada. menuitem debe ser un elemento secundario directo de menu. El siguiente código podría romper el comportamiento semántico:

 <!-- Wrong, don't do this -->
<ul role="menu">
  <li>
    <a href="#" role="menuitem">Item 1</a>
  </li>
</ul>

Los usuarios expertos esperan que ciertas combinaciones de teclas funcionen con menús y barras de menú. Según la Guía de prácticas para autores de ARIA (APG), esto incluye lo siguiente:

  • Intro y la Barra espaciadora para seleccionar elementos de menú.
  • Usa las teclas de flecha en todas las direcciones para navegar entre los elementos.
  • Las teclas Inicio y Fin para mover el foco al primer o al último elemento, respectivamente
  • a-z para enfocar el siguiente elemento del menú con una etiqueta que comienza con el carácter escrito.
  • Presiona Esc para cerrar el menú.

Si un lector de pantalla detecta un menú, el software puede cambiar automáticamente el modo de navegación, lo que habilita el uso de las combinaciones de teclas mencionadas anteriormente. Es posible que los usuarios sin experiencia del lector de pantalla no puedan usar el menú porque no conocen estas combinaciones de teclas ni cómo usarlas.

Es lo mismo para los usuarios de teclado que podrían prever que pueden usar Mayúsculas y Mayúsculas + Tab.

Hay muchos aspectos que debes tener en cuenta a la hora de crear menús y barras de menú, y decidir si es adecuado utilizarlos en primer lugar. Cuando creas un sitio web típico, solo necesitas el elemento de navegación con una lista y vínculos. Esto también incluye las aplicaciones de una sola página (SPA) o aplicaciones web. La pila subyacente no importa. A menos que compiles algo muy parecido a una aplicación para computadoras, evita los roles de menú.

Recursos adicionales

Hero image de Mick Haupt