6 buenas prácticas para crear un menú desplegable responsive
Spanish (Español) translation by Eva Collados Pascual (you can also view the original English article)
Construir un menú desplegable y responsive es una labor que puede resultar confusa. Existen muchas decisiones a tomar, tanto en las fases relacionadas con el diseño como en las relacionadas con el desarrollo. La mejor solución depende de las características del sitio web o de la aplicación que estés creando el menú desplegable en HTML. Sin embargo, también existen algunas buenas prácticas recomendadas para cualquier tipo de menú desplegable responsive.
He recopilado estas mejores prácticas mientras escribía mi tutorial sobre cómo hacer un menú desplegable y responsive con flexbox. Dado que es un tutorial más bien práctico, no me quedó mucho espacio para explicar qué decisiones relacionadas con el diseño y el desarrollo del menú responsive tuve que tomar, así que aquí estamos. Estas recomendaciones no sirven solo para los menús desplegables creados con flexbox, sino para cualquier tipo de menú desplegable responsive. Así que, ¡continúa leyendo y descubre cómo hacer un menú desplegable en HTML!
1. Utiliza el diseño "mobile-first" para tu menú desplegable en HTML
Problema
Aunque puede parecer más sencillo diseñar primero un menú para pantallas de equipos de sobremesa y después adaptarlo a las pantallas más pequeñas, este no suele ser el caso, especialmente si tu menú responsive tiene un submenú desplegable.
Si diseñas primero un menú desplegable con HTML para dispositivos de sobremesa, puede ponerse rápidamente complicado y podrías acabar con un largo menú en dispositivos móviles, y los usuarios tendrán que continuar desplazándose sin siquiera llegar a ver su final.
Solución
Puedes implementar el diseño mobile-first en tus menús desplegables usando media queries o consultas de medios min-width
en lugar de las de max-width
:
@media all and (min-width: 960px) { // ... }
Con media queries min-width
, el diseño móvil del menú responsive será el predeterminado y añadirás reglas para pasar después a diseñar para tabletas, y después para ordenadores de sobremesa (o, en algunos casos, ni siquiera tendrás que crear un diseño específico para tabletas).
Esto también es importante desde un punto de vista del rendimiento. Si utilizas un diseño mobile-first para tu menú desplegable HTML, los dispositivos móviles (que frecuentemente acceden a tu sitio a través de una conexión de datos limitados o una conexión wifi precaria) tendrán que evaluar algunas reglas de estilo, ya que podrán saltar algunos bloques de media queries.



2. Reordenar los elementos del menú desplegable HTML
Problema
En muchos casos, podrías querer mostrar elementos de menú y de submenú en distinto orden para los teléfonos móviles, para las tabletas, y para las pantallas de equipos de sobremesa, pero quieres mantener la estructura lógica del HTML y la accesibilidad.
Solución
Con la propiedad order
, podrás cambiar el orden visual de los elementos del menú responsive al mismo tiempo que mantienes el DOM sin cambios.
Como regla general, los elementos del menú de la estructura HTML deberían seguir el mejor orden para los usuarios que utilicen lectores de pantalla u otras tecnologías asistivas. No olvides que los robots de los motores de búsqueda son similares a los lectores de pantalla en el sentido de que solo ven la estructura del menú desplegable HTML, pero no el orden visual.
Aquí tienes un ejemplo de un menú responsive consistente en botones de llamada a la acción y enlaces de menú. Queremos que las llamadas a la acción o CTA aparezcan al principio del menú en los dispositivos móviles y en las tabletas, y al final del menú en los equipos de sobremesa. En el HTML, los enlaces de menú vendrán primero (sin embargo, esto no es obligatorio, en algunos casos, podrías querer poner los botones de llamada a la acción en primer lugar para los usuarios de tabletas).
<nav> <ul> <li class="mlink">Menu Link 1</li> <li class="mlink">Menu Link 2</li> <li class="mlink">Menu Link 3</li> <li class="cta">CTA 1</li> <li class="cta">CTA 2</li> </ul> </nav>
Como el valor predeterminado de order
es 0, no tienes que cambiarlo para el primer elemento. Para el segundo elemento en el orden visual, su valor será 1. Para el tercero, será 2, y así consecutivamente. Observa que order
también puede tomar valores negativos. De manera que, el CSS será como sigue:
ul { display: flex; } .mlink { order: 1; } @media all and (min-width: 960px) { .mlink { order: 0; } }
Nota: la propiedad order
solo funciona con las maquetaciones CSS creadas con flexbox y con grid, así que si quieres usarla tienes que añadir o bien display: flex;
o display: grid;
al elemento de menú padre.



3. Utiliza receptores de eventos en los menús desplegables para dispositivos móviles y tabletas
Problema
En dispositivos de sobremesa, el submenú se activa normalmente usando la pseudoclase :hover
. Cuando los usuarios situen el puntero sobre el menú padre, el submenú asociado emerge en la pantalla. Cuando se mueven fuera de él, el submenú desaparece. Sin embargo, no existe la pseudoclase :hover
en teléfonos móviles, ni en tabletas, ni en otros dispositivos móviles.
Solución
Usando receptores de eventos de JavaScript, puedes abrir y cerrar el submenú siempre que el usuario haga clic o toque el elemento de menú padre. El método addEventListener()
es parte de la API del DOM y está integrado en cualquier navegador actual browser y en las vesiones superiores a IE9.
El siguiente código procede de mi anteriormente mencionado tutorial para crear un menú con flexbox , y añade o elimina la clase .submenu-active
siempre que el usuario haga clic en el elemento de menú padre. Los estilos display
del .submenu-active
pueden ser añadidos con CSS.
/* Activate Submenu */ function toggleItem() { if (this.classList.contains("submenu-active")) { this.classList.remove("submenu-active"); } else if (menu.querySelector(".submenu-active")) { menu.querySelector(".submenu-active").classList.remove("submenu-active"); this.classList.add("submenu-active"); } else { this.classList.add("submenu-active"); } } /* Event listeners */ for (let item of items) { if (item.querySelector(".submenu")) { item.addEventListener("click", toggleItem, false); } }
El loop for...of
recorre todos los elementos de menú, y después el bloque if
selecciona aquellos que tengan un submenú y les añade un receptor de eventos clic. La función personalizada toggleItem()
es invocada siempre que el usuario haga clic o de un toque al elemento de menú que contenga un submenú.
Existen muchos eventos en la API del DOM a los que puedes dirigirte con receptores de eventos. Para los dispositivos táctiles, click
y touchstart
son los receptores más usados. Arriba, hemos usado click
, ya que funciona tanto con un clic como con un toque, mientras que touchstart
solo funciona para los toques y no para los clics.
Nota: puedes dirigirte solo a un tipo de evento con el método addEventListener()
. Esta es una importante diferencia comparado con jQuery en donde puedes añadir más de un evento al método on()
usado para receptores de eventos.
4. Elige entre hacer clic o situarse sobre un elemento para dispositivos de sobremesa
Problema
Ahora que tu submenú funciona en teléfonos móviles y en tabletas, aquí tenemos otro problema: en los dispositivos de sobremesa, podrías querer permitir que los usuarios muestren los submenús al situar el puntero sobre un elemento en lugar de tener que hacer un clic. Sin embargo, si ya has añadido el receptor del evento clic para que muestre el submenú en dispositivos táctiles, el menú desplegable HTML de los equipos de sobremesa reaccionarán tanto al hacer clic como al situar el puntero sobre un elemento.
Las dos acciones de usuario pueden interferir con facilidad entre sí, lo que puede ocasionar confusión o, en algunos casos, incluso romper el diseño del menú responsive.
Solución
En las pantallas de los dispositivos de sobremesa, debes determinar si el submenú se mostrará al hacer hover o al hacer clic. Por lo general, diría que si estás creando una app web, optes por el clic, ya que ese es el comportamiento que la mayoría de los usuarios de aplicaciones esperarían. Y, si estás construyendo un sitio web, elige hover, ya que es el comportamiento más natural en un sitio web.
Si eliges clic
Si decides mantener el manejador de eventos clic para equipos de sobremesa, hay un pequeño problema de usabilidad a resolver. Cuando el usuario navega fuera del área del menú, el submenú no se cerrará por sí solo (lo que sería un comportamiento natural con la acción hover). Para cerrar el submenú, el usuario tendrá que navegar de vuelta al elemento del menú padre y hacer de nuevo clic, algo que no constituye una experiencia de usuario ideal.
Para solucionarlo, puedes usar el siguiente script que permite que el usuario cierre el submenú haciendo clic en cualquier sitio de la página.
/* Close Submenu From Anywhere */ function closeSubmenu(e) { let isClickInside = menu.contains(e.target); if (!isClickInside && menu.querySelector(".submenu-active")) { menu.querySelector(".submenu-active").classList.remove("submenu-active"); } } /* Event listener */ document.addEventListener("click", closeSubmenu, false);
Esto añade un receptor de eventos al objeto document
y elimina la clase .submenu-active
cuando tenga lugar un clic dentro del documento, pero fuera del área del menú desplegable en HTML.
Si eliges situar el puntero sobre un elemento
Si eliges hover, tendrás que detectar el tamaño de la ventana de visualización con JavaScript y añadir una declaración if
extra al receptor de eventos para comprobar si su anchura es más pequeña que el "breakpoint" de la media query. Puedes usar la propiedad clientWidth
del objeto document
para detectar la anchura de la ventana de visualización (excluyendo cualquier desplazamiento).
Así que, en el anterior código, el receptor de eventos recorre esas llamadas que la función personalizada toggleItem()
cambiará a lo que sigue:
if (document.documentElement.clientWidth < 960) { for (let item of items) { if (item.querySelector(".submenu")) { item.addEventListener("click", toggleItem, false); } } }
En el CSS, necesitarás añadir las reglas responsables del diseño del submenú en equipos de sobremesa a la pseudoclase :hover
.
5. Utiliza la etiqueta <a> sin el atributo href para los elementos del menú responsive vacíos
Problema
En muchas ocasiones, los elementos de menú padres solo servirán para abrir o cerrar el correspondiente submenú, pero no enlazarán a ningún sitio. Sin embargo, si quieres mantener la estructura del HTML consistente y la hoja de estilo CSS simple, tendrás que añadir también la etiqueta de ancla <a href="#">
a esos elementos de menú "vacios".
En ese caso, sin embargo, cuando el usuario haga clic en el elemento de menú padre para abrir o cerrar el submenú, la página se refrescará y saltará a la parte superior en los dispositivos móviles. Esto es especialmente negativo en el caso de que tengas menús desplegables largos.
Solución
Una frecuente solución a este problema de los menús desplegables consiste en añadir el valor "javascript: void(0);"
al atributo href
. Sin embargo, esto está considerado como una mala práctica, ya que utiliza una pseudo URL que devuelve undefined
como valor lo que puede dar como resultado diferentes errores y comportamientos inesperados.
La forma más sencilla de solucionarlo consiste en usar la etiqueta <a>
sin el atributo href
para esos elementos del menú responsive vacíos, lo cual es una solución válida, dado que href no es un atributo necesario. Según los documentos de W3C:
“El atributohref
en los elementosa
yarea
no es necesario; cuando esos elementos no tienen atributoshref
no crean hipervínculos.”
Sin embargo, se dan dos problemas con las etiquetas <a>
:
- Estas no tienen un teclado accesible al haber sido omitidas en el orden de pestañas predeterminado. Puedes resolver esto añadiendo el atributo
tabindex="0"
a cada etiqueta<a>
que no tenga un atributohref
. - Incluso si los elementos vacíos
<a>
son incluídos en el orden de pestañas, los usuarios no podrás abrir ni cerrar el correspondiente submenú pulsando Enter en el teclado. Esto puede solucionarse creando un receptor de eventos para el eventokeypress
.
De manera que, así es como estructuramos el HTML:
<ul class="menu"> <li class="item"><a href="home.html">Home</a></li> <li class="item"><a href="about.html">About</a></li> <li class="item has-submenu"> <a tabindex="0">Services</a> <ul class="submenu"> <li class="subitem"><a href="service1.html">Service 1</a></li> <li class="subitem"><a href="service2.html">Service 2</a></li> <li class="subitem"><a href="service3.html">Service 3</a></li> </ul> </li> <li class="item has-submenu"> <a tabindex="0">Plans</a> <ul class="submenu"> <li class="subitem"><a href="plan1.html">Plan 1</a></li> <li class="subitem"><a href="plan2.html">Plan 2</a></li> <li class="subitem"><a href="plan3.html">Plan 3</a></li> </ul> </li> <li class="item">li><a href="blog.html">Blog</a></li> <li class="item"><a href="contact.html">Contact</a></li> </ul>
Para el receptor de eventos, puedes usar la misma función personalizada toggleItem()
que creamos para abrir y cerrar el submenú. Solo tienes que añadir un receptor de eventos keypress al arterior bucle toggleItem()
de la siguiente manera:
for (let item of items) { if ( item.querySelector(".submenu")) { item.addEventListener("click", toggleItem, false); item.addEventListener("keypress", toggleItem, false); } }
6. Haz que los iconos estén disponibles offline
Problema
Si estás usando blibiotecas de fuentes de iconos como FontAwesome para los submenús desplegables, como la frecuente flecha hacia abajo, los iconos desaparecerán cuando el sitio web o la app es accedido offline. Observa que la disponibilidad offline también concierne a la accesibilidad.
Solución
La solución a este problema es relativamente simple. En lugar de cargar las bibliotecas de iconos desde tu CDN, también puedes cargarlos de forma local. Por ejemplo, aquí tienes como puedes alojar Font Awesome por ti mismo. Si solo cargas las partes de las bibliotecas que necesitas para tu sitio, podrías incluso ahorrar tiempo de carga, aunque esto también depende de cómo esté estructurada la biblioteca de iconos.



¡Con esto terminamos con las mejores prácticas sobre cómo hacer un menú desplegable HTML responsive!
Construir un menú responsive y desplegable es realmente sencillo, sin embargo, existen muchos detalles a los que debes prestar atención. Debe funcionar en distintos dispositivos, reaccionar adecuadamente a distintos eventos, ser accesible para los usuarios que navegan mediante el teclado, estar disponible offline, y mucho más.
Si piensas en las formas en las que se accederá a tu sitio web o aplicación, será más fácil decidir cómo enfocar todos los problemas que puedan surgir cuando los usuarios intenten usar tu submenú.
¿Conoces algunas otras mejores prácticas que consideres merecen ser mencionadas sobre cómo hacer un menú desplegable en HTML? ¡Cuéntanoslo!
Guarda esto: Cómo hacer un menú desplegable en HTML que sea responsive
Echa un vistazo a mi menú desplegable responsive en CodePen, el cual hace uso de todas las mejores prácticas que hemos visto en esta guía. Guárdalo, ¡y modifícalo para adaptarlo a tus proyectos!
Aprende más sobre cómo diseñar sistemas de navegación en Tuts+
En Tuts+ tenemos muchos otros tutoriales sobre cómo hacer un menú desplegable en HTML y sobre cómo diseñar sistemas de navegación y, ¡sumérgete y aprende!
- FlexboxHow to Build a Striped Navigation With FlexboxGeorge Martsoukos
- Bootstrap 4How to Make the Bootstrap Navbar Dropdown Work on HoverGeorge Martsoukos
- Navigation DesignHow to Build an Off-Canvas Menu With CSS and a Touch of JavaScriptGeorge Martsoukos
- UX3 Principles for Strong User Experience Through NavigationJoel
Subscribe below and we’ll send you a weekly email summary of all new Web Design tutorials. Never miss out on learning about the next big thing.
Update me weekly