Mar 7, 2010
Menúes desplegables solo con CSS (Sin JavaScript)
Muchos sitios que mantienen su información administrada en categorías, usa menúes desplegables para ir recorriendo los árboles de esta, y la mayoría de veces estos estan hechos en flash o con JavaScript, ensuciando el código y volviendolo complicado.
Lo que pocos saben es que se puede hacer un menu desplegable totalmente funcional sin necesidad de usar mas que HTML y CSS, sin incluir JS’s, librerias ni nada.
Para empezar, vamos a armar un menu o barra de navegación estandar, esto se hace con ul’s y li’s, pero anidados, asi vamos a tener hasta 3 niveles:
<ul class="menu"> <li> <a href="#">Opcion 1</a> <ul> <li> <a href="#">Sub nivel 1</a> </li> <li> <a href="#">Sub nivel 2</a> </li> </ul> </li> <li> <a href="#">Opcion 2</a> <ul> <li> <a href="#">Sub nivel 1/2</a> </li> <li> <a href="#">Sub nivel 2/2</a> </li> </ul> </li> <li> <a href="#">Opcion 3</a> <ul> <li> <a href="#">De tercer nivel</a> <ul> <li> <a href="#">Ejemplo opcion</a> </li> </ul> </li> <li> <a href="#">Sub nivel 2</a> </li> </ul> </li> </ul>
Luego de esto tendremos un listado ordenado digno de un menu estático y de indice de libro, asi que a estiliar:
Como saben se puede hacer de 2 formas, ipo menú al costado de la página (vertical) o al estilo de barra de navegación (horizontal), primero lo vamos hacer tipo menú.
Lo primero que debemos hacer es sacar las decoraciones de lista, asi lo vamos a tener en forma de menú, y por otro lado, ocultar los submenues que no se tienen que ver de entrada:
ul.menu {
padding: 0;
margin: 0;
list-style:none;
}
ul.menu ul {
list-style:none;
display: none;
padding: 0;
margin: 0;
}
ul.menu li {
width: 100px;
border: 1px solid;
}
De esta forma vamos a tener algo mas parecido a un menú moderno, ahora nos toca hacer que al pasar por una opción, se desplieguen las sub-opciones, para eso solo deberomos agregar:
ul.menu li:hover > ul {
display:block;
}
De esta manera le decimos que al li:hover (con el cursor arriba), al siguien te <ul>, y por eso usamos li:hover > ul y no li:hover ul, que esto tambien afectaría a los submenues de tercer nivel.
Una vez hecho esto, tendremos a los submenues abriendose dentro del menú, para evitar esto, debemos marcar que el ul tiene una pocición absoluta, asi gana su propio espacio dentro de la visualización del html, pero a la vez necesitan estar en una posición relativa para que pertenezcan al padre.. la solución: Marcando a los li contendores que son relativos, y a los ul absolutos, a la vez le añadimos al ul un left para no pisar el menu y un top negativo para estar a la altura del primer li contenedor, en fin nos quedaría:
ul.menu ul {
list-style:none;
display: none;
padding: 0;
margin: 0;
position: absolute;
left:100px;
top:-1px;
}
ul.menu li {
width: 100px;
border: 1px solid;
position: relative;
}
En fin, ahi tendriamos nuestro menú desplegable, andando y listo para usar. PERO NO ES ASI!!!
Arreglandolo para IE:
Jeje, bueno para los que recién empiezan en maquetación se van a tener que ir a acostumbrando a esto, para lo que ya estan acostumbrados les habrá parecido raro que no haya hablado de esto, pero en lo personal prefiero tener un código limpio y mandar los “hacks” al final.
Problema: El selector CSS :hover como el resto de los selectores CSS, tiene que funcionar en cualquier elemento, pero el IE solo lo hace en los “a”, lamentablemente aca vamos a tener que poner un poco de JS, pero la ventaja correrá en el en el resto de los navegadores va a seguir funcionando igual
.
Vi varias soluciones pero ninguna me convenció, asi que hice mi propio metodo JScriptero:
window.onload = function () {
var obj = document.getElementById('navbar');
var lils = obj.getElementsByTagName('li');
for ( i = 0 ; i < lils.length; i++) {
li = lils[i];
li.onmouseover = function () {
if (ul = this.getElementsByTagName('ul')[0])
ul.style.display = "block";
}
li.onmouseout = function () {
if (ul = this.getElementsByTagName('ul')[0])
ul.style.display = "none";
}
}
}
Obviamente ese JS sirve para todos los browsers, asi que para aplicarlo (lo hice en el mismo documento), usé el hack IE <!–[if IE]>…<![endif]–>, asi, el resto de los browsers lo tomaria como un comentario HTML y nunca lo ejecutaría:
En fin el código funcional esta aca: http://pastebin.com/txUTNTQs
Tips relacionados:

Ultimos comentarios