Icono del sitio Tursos

Como Hacer un Menú Desplegable Multinivel Usando solo CSS

En este tutorial aprenderemos a hacer un sencillo menú desplegable con soporte para infinitos niveles usando HTML y CSS.

Estructura HTML

Trabajaremos con una lista con clase de «nav», que almacenara los items del menú:

<!DOCTYPE HTML>
<html>
<head>
	<title>Menu desplegable usando solo CSS</title>
	<link rel="stylesheet" href="estilos.css" />
</head>
<body>
<ul class="nav">
	<li><a href="">Home</a></li>
	<li><a href="">Servicios</a></li>
	<li><a href="">Acerca</a></li>
	<li><a href="">Contacto</a></li>
</ul>
</body>
</html>

Los submenús se desplegaran cuando el usuario pase el cursor, estos iran como listas dentro de listas(ul > li > ul). Este ejemplo funcionara con cualquier cantidad de submenús, eso quiere decir que puedes incluir los niveles de menús que quieras, en este caso tendremos 3 niveles:

<ul class="nav">
	<li><a href="">Home</a></li>
	<li><a href="">Servicios</a>
		<ul>
			<li><a href="">Diseno grafico</a></li>
			<li><a href="">Diseno web</a>
				<ul>
					<li><a href="">Submenu 1</a></li>
					<li><a href="">Submenu 2</a></li>
					<li><a href="">Submenu 3</a></li>
					<li><a href="">Submenu 4</a></li>
					<li><a href="">Submenu 5</a></li>
				</ul>
			</li>
			<li><a href="">Marketing</a>
				<ul>
					<li><a href="">Submenu 1</a></li>
					<li><a href="">Submenu 2</a></li>
					<li><a href="">Submenu 3</a>
						<ul>
							<li><a href="">Submenu 1</a></li>
							<li><a href="">Submenu 2</a></li>
							<li><a href="">Submenu 3</a></li>
							<li><a href="">Submenu 4</a></li>
						</ul>
					</li>
				</ul>
			</li>
			<li><a href="">SEO</a></li>
		</ul>
	</li>
	<li><a href="">Acerca</a>
		<ul>
			<li><a href="">Historia</a></li>
			<li><a href="">Mision</a></li>
			<li><a href="">Vision</a></li>
		</ul>
	</li>
	<li><a href="">Contacto</a></li>
</ul>

Código CSS

Empezaremos con un reset basico y algo de decoración para el menu:

* {
font-family:sans-serif;
list-style:none;
text-decoration:none;
margin:0;
padding:0;
}

.nav > li {
float:left;
}

.nav li a {
background:#0c9ba0;
color:#FFF;
display:block;
border:1px solid;
padding:10px 12px;
}

.nav li a:hover {
background:#0fbfc6;
}

En la linea 9, se especifica que solo los li que sean descendientes directos del primer ul tengan float: left, esto es para que solo el menu principal sea horizontal y los submenús se mantengan en vertical:

Por defecto todos los submenús no serán visibles, los ocultaremos usando display: none.

.nav li ul {
display:none;
position:absolute;
min-width:140px;
}

Todos los submenús tendrán un ancho minimo de 140px para que no se vean desiguales y llevaran position: absolute para que no afecten el ancho del menu principal.

Proseguimos con la parte que hara que se muestre el submenu oculto:

.nav li:hover > ul {
display:block;
}

En este código le estamos indicando que cuando el cursor pase sobre cualquier li su descendiente ul se muestre(display: block).

El problema ahora es que los submenús de segundo nivel en adelante se están mostrando pero no como deberían:

Lo que tenemos que hacer es que estos se muestren a la derecha de su respectivo ancestro li:

.nav li ul li {
position:relative;
}

.nav li ul li ul {
right:-140px;
top:0;
}

Los submenús de segundo nivel tendran right: -140px, para empujarlos hacia la derecha, es importante notar que este valor es el mismo que el que definimos anteriormente como ancho mínimo, y ademas tendra top: 0 esto es para que se posicione al mismo nivel que su ancestro li que tiene position: relative.

Esto afectara todos los submenús de segundo nivel en adelante:

Añadir un indicador a los elementos con submenu

Investigando por internet encontre la forma de anadir un indicador a los elementos que contengan submenus sin hacer uso de JS y aqui lo comparto:

Lo primero es añadir el elemento que hará de indicador al lado de cada enlace del menu, en este caso estamos usando una flechita (si prefieres usar una imagen tambien funcionara) su código HTML es &#9660:

<ul class="nav">
	<li>
		<a href="#">Home<span class="flecha">▼</span></a>
	</li>
	<li>
		<a href="#">Servicios<span class="flecha">&#9660</span></a>
		<ul>
			<li><a href="#">Diseno grafico<span class="flecha">&#9660</span></a></li>
			<li>
				<a href="#">Diseno web<span class="flecha">&#9660</span></a>
				<ul>
					<li><a href="#">Submenu 1<span class="flecha">&#9660</span></a></li>
					<li><a href="#">Submenu 2<span class="flecha">&#9660</span></a></li>
					<li><a href="#">Submenu 3<span class="flecha">&#9660</span></a></li>
					<li><a href="#">Submenu 4<span class="flecha">&#9660</span></a></li>
					<li><a href="#">Submenu 5<span class="flecha">&#9660</span></a></li>
				</ul>
			</li>
			<li>
				<a href="#">Marketing<span class="flecha">&#9660</span></a>
				<ul>
					<li><a href="#">Submenu 1<span class="flecha">&#9660</span></a></li>
					<li><a href="#">Submenu 2<span class="flecha">&#9660</span></a></li>
					<li>
						<a href="#">Submenu 3<span class="flecha">&#9660</span></a>
						<ul>
							<li><a href="#">Submenu 1<span class="flecha">&#9660</span></a></li>
							<li><a href="#">Submenu 2<span class="flecha">&#9660</span></a></li>
							<li><a href="#">Submenu 3<span class="flecha">&#9660</span></a></li>
							<li><a href="#">Submenu 4<span class="flecha">&#9660</span></a></li>
						</ul>
					</li>
				</ul>
			</li>
			<li><a href="#">SEO<span class="flecha">&#9660</span></a></li>
		</ul>
	</li>
	<li>
		<a href="#">Acerca<span class="flecha">&#9660</span></a>
		<ul>
			<li><a href="#">Historia<span class="flecha">&#9660</span></a></li>
			<li><a href="#">Mision<span class="flecha">&#9660</span></a></li>
			<li><a href="#">Vision<span class="flecha">&#9660</span></a></li>
		</ul>
	</li>
	<li>
		<a href="#">Contacto<span class="flecha">&#9660</span></a>
	</li>
</ul>

Ahora lo que haremos sera definir que por defecto esta flecha este oculta en todos los elementos del menu:

.nav li .flecha{
font-size: 9px;
padding-left: 6px;
display: none;
}

Tambien le reduci el tamano de la fuente y lo aleje un poco del texto para que se vea bien.

La parte esencial de esto es la siguiente: vamos a usar la psuedo-clase CSS3 :not en combinación con :last-child para excluir a todos los elementos del menu que no contengan submenus (todos los <a> que no sean :last-child) y solo afectar a los span.flecha de los que si:

.nav li a:not(:last-child) .flecha {
display: inline;
}

El resultado:

Pueden leer mas acerca de este selector en este enlace, lamentablemente solo es soportado por los ultimos navegadores (incluyendo IE9).

Conclusión

Cabe notar que este ejemplo tiene ciertas limitaciones como la relantizar la desaparición del submenu cuando el cursor deja el elemento, sin embargo es una buena alternativa para cuando necesitamos crear un menu desplegable lo mas rapido posible.