Menú de dos niveles sólo con CSS

Un menú de dos niveles sin usar JavaScript, y con sólo unas cuantas líneas de CSS.

Cuando necesitamos hacer un menú de dos niveles, es muy común recurrir a alguna librería de JavaScript que haga la mayor parte del trabajo pesado por nosotros, sin embargo hacerlo solo con CSS no solo es mucho más simple, sino que de paso elimina casi todos los puntos potenciales de falla.

El HTML

Empezamos con una lista no ordenada (UL) para el primer nivel, y otra lista no ordenada dentro de cada LI que va a tener un sub-menu.

<ul class="menu">
  <li>
    <a href="#">Homepage</a>
  </li>
  <li>
    <span>Categorías</span>
    <ul>
      <li><a href="#">Artículos</a></li>
      <li><a href="#">Notas</a></li>
      <li><a href="#">Páginas</a></li>
    </ul>
  </li>
  <li>
    <span>Archivo</span>
    <ul>
      <li><a href="#">Meses</a></li>
      <li><a href="#">Años</a></li>
      <li><a href="#">Archivo completo</a></li>
    </ul>
  </li>
  <li>
    <a href="#">Contacto</a>
  </li>
</ul>

Los títulos en los elementos que tienen un menú secundario no son links (a), sino span, porque el click no es necesario en estos elementos.

Nota: Este es el unico HTML que tendremos durante el resto del ejemplo, asi que en los siguientes bloques sólo pondré el el CSS y el resultado.

Primer nivel

Para crear el menú de primer nivel, ocultamos los ul internos y volvemos .menu un elemento Flex con los items al centro. Si necesitas saber qué rollo con esto acá hay una introducción a Flexbox.

También le quitamos el estilo de lista a .menu y .menu ul con list-style: none.

.menu{
  display: flex;
  justify-content: center;
  list-style: none;
}
.menu ul{
  display: none;
  list-style: none;
}

Ajuste de estilo

Normalizamos la apariencia de los links y los spans, y les agregamos padding a los lados:

.menu{
  display: flex;
  justify-content: center;
  list-style: none;
}
.menu ul{
  display: none;
  list-style: none;
}
.menu a,
.menu span{
  text-decoration: none;
  padding: 0 .5rem;
}

Segundo nivel

Ahora hacemos que el menú de segundo nivel (.menu ul) aparezca con display: block cuando el cursor esté sobre su contenedor (li) y lo posicionamos de manera absoluta al 100% de distancia del borde superior y a 0 distancia del borde izquierdo de su contenedor.

Para lograr este posicionamiento le damos position: relative al elemento contenedor li.

.menu{
  display: flex;
  justify-content: center;
  list-style: none;
}
.menu ul{
  display: none;
  list-style: none;
  position: absolute;
  top: 100%;
  left: 0;
}
.menu li:hover ul{
  display: block;
}
.menu li{
  position: relative
}
.menu a,
.menu span{
  text-decoration: none;
  padding: 0 .5rem;
}

Segundo nivel: estilo visual

Normalizamos el padding del menu de segundo nivel, y le agregamos un color de fondo y una sombra para separarlo del resto. También le damos un ancho mínimo.

.menu{
  display: flex;
  justify-content: center;
  list-style: none;
}
.menu ul{
  display: none;
  list-style: none;
  position: absolute;
  top: 100%;
  left: 0%;
  padding: 1rem;
  background: white;
  box-shadow: 0 2px 16px rgba(0,0,0,.25);
  min-width: 12rem;
}
.menu li:hover ul{
  display: block;
}
.menu li{
  position: relative
}
.menu a,
.menu span{
  text-decoration: none;
  padding: 0 .5rem;
}

Y listo, con este código base ya puedes dar rienda suelta a tu creatividad y enfocarte en el estilo visual de tu menú sin necesidad de estar lidiando con librerías o funciones en JavaScript.


Nota: este es un menú muy básico, y no toma en cuenta el funcionamiento en dispositivos sin cursor (como un teléfono o una tablet). Más adelante retomaré en un ejemplo lo necesario para que sí funcione en esos dispositivos y actualizaré este párrafo con un link a ese ejemplo.

Responder a

Menú de dos niveles sólo con CSS

o Cancelar