Vamos a hacer sólo con CSS un menú desplegable. Este menú, al ser sólo con CSS, no funcionará en Internet Explorer con versión 6 o menor. Quizás en la 7 si vaya, no lo sé.
El menú, simple, sin ningún tipo de estilo adicional que vamos a contar aquí es el siguiente.
Al final lo tienes con algo más de color. Si le das a "opcion 2", "una c" verás que hay tres niveles. El estilo aquí propuesto en principio vale para cualquier número de niveles que pongamos.
Empezamos haciendo el código html, que es más sencillo. Simplemente unas etiquetas <ul> y <li> convenientemente anidadas:
<ul class="menu">
<li>opcion 1
<ul>
<li>una a</li>
<li>una b</li>
</ul>
</li>
<li>opcion 2
<ul>
<li>una c
<ul>
<li>otra</li>
<li>mas</li>
</ul>
</li>
<li>una d</li>
</ul>
</li>
</ul>
Por supuesto, podríamos poner enlaces <a> en las opciones del menú.
Lo primero que vamos a hacer es ocultar los submenús para no se vean. Para ello, a los <ul> por debajo de los <li> les ponemos un display:none. También hay que quitarles los puntitos que salen con list-style-type:none;
ul.menu
{
list-style:none;
}
ul.menu ul /* Para todos los ul debajo del
ul.menu */
{
display:none;
list-style:none;
}
Ahora deberíamos hacerlos visibles cuando el ratón se coloca encima del <li> correspondiente. Para ello usamos li:hover y esto es el motivo por el que no funciona en Internet Explorer, porque no hace caso de los hover salvo que vayan sobre una etiqueta <a>. El estilo CSS sería
/* Esto afecta a todos los ul inmediatamente debajo (el
> ) de un li que a su vez esté dentro de un ul.menu */
ul.menu li:hover > ul
{
display:block;
}
Haciéndolo de esta forma, con el >, sólo afecta a los <ul> que están justo dentro de un <li>, visualizándose sólo las subopciones de la opción actual.
Con esto, el menú quedaría así
Si jugamos un poco, vemos que según van apareciendo los submenús, se mueve todo. También vemos (por el borde que le he puesto), que los elementos ocupan casi el 100% de la página.
Lo segundo es fácil de solucionar, basta ponerles un width. Además, es necesario fijar un ancho para saber dónde dibujar los submenus, a la distancia justa.
Lo del movimiento es algo más complejo de evitar. Para evitar esto, tenemos que sacar los submenús del flujo normal de html. Les daremos una posición absoluta, para que aparezcan donde nosotros queramos.
No es bonito poner una posición absoluta global respecto a la página, porque tendríamos que calcularla cada vez que toquemos el texto o modifiquemos la página. Afortunadamente, position:absolute situa un elemento en una posición absoluta "respecto al componente padre que también esté posicionado, entre otras con position:relative".
Esto es estupendo. Si a cada <li> le ponemos position:relative, no altera su posición en la página, pero podemos calcular la posición de sus submenús con position:absolute y las coordenadas son relativas a las del <li> en cuestión.
En fin, que haciendo todo esto y jugando un poco con las medidas de pixels para que todo cuadre, el estilo CSS queda así
ul.menu
{
list-style:none;
}
ul.menu li
{
position:relative; /*
Las coordenadas de los ul inferiores serán relativas al <li>
que los contiene */
width:70px;
}
ul.menu ul
{
position:absolute; /*
Esta posición es relativa al <li> que contiene a este <ul>
*/
left:30px; /* Para que
no monte sobre el <li> */
top:-1px;
display:none;
list-style:none;
}
ul.menu li:hover > ul
{
display:block;
}
Listo, con esto tenemos el menú hecho como lo vimos al principio.
Aunque nunca me he distinguido por mi gusto artístico, el menú de arriba a pelo queda feo. Le doy aquí un poco de color, pero seguro que puedes hacerlo más mejor con poco esfuerzo.
Aquí tienes un ejemplo mucho más bonito y si indagas, encontrarás el javascript necesario para hacerlo funcionar en Internet Explorer.
Si queremos el primer menú horizontal, se puede hacer con realativa facilidad, aunque debemos complicar un poco el CSS si queremos varios niveles.
Los <li> de primer nivel los tenemos que poner con display:inline (quizás también display:float, aunque no he probado).
Los <ul> debajo de los <li> de primer nivel llevan unas posiciones absolutas distintas, ya que deben salir debajo de los <li> y no a su derecha.
El resto de los <ul> siguen como hasta ahora. El CSS resultante es lo que teníamos antes más este añadido para tratar distinto los primeros <ul>
ul.menu> li > ul /*
Solo para los ul debajo de los li de primer nivel. */
{
position:absolute;
left:-41px;
top:19px;
display:none;
list-style:none;
}
ul.menu > li /* Sólo para li de
primer nivel */
{
display:inline;
}
Y este es el resultado
En html, cuando vamos poniendo distintos tags, el navegador los dibuja consecutivamente, en el mismo orden que los hemos puesto. Esto es lo que se llama flujo normal de html.
Si mediante CSS usamos técnicas de posicionamiento de bloques, como position, float, etc, los elementos afectados se salen del flujo normal. El navegador los siturará donde los hayamos posicionado e irá poniendo consecutivamente el resto. Podemos incluso ponerlos superpuestos.