Un completo curso de diseño gráfico, ilustración, diseño web y tipografía.

Menús desplegables con CSS

por Patrick Griffiths y Dan Webb

Los menús desplegables en “DHTML” implican utilizar grandes bloques de JavaScript con muchos arreglos específicos de un navegador u otro que hacen que un HTML que por otro lado esté limpio y estructurado semánticamente acabe siendo inaccessible. Oh, ¡cómo soñaríamos con un método ligero, accesible, que vaya con los estándares y compatible con todos los navegadores! Entran en escena nuestros menús desplegables, los “Suckerfish Dropdowns”.

Presentamos el código

Para empezar, debemos emplear el mejor método para definir un menú de navegación — una lista. En este ejemplo, trabajaremos en una lista simple sin numerar {Marcamos los saltos de línea con ». –Ed.}

<ul>
  <li>Sunfishes
    <ul>
      <li><a href="">Blackbanded»

        sunfish</a></li>
      <li><a href="">Shadow bass</a></li>
      <li><a href="">Ozark bass</a></li>

      <li><a href="">White crappie</a></li>
		</ul>
	</li>

  <li>Grunts
    <ul>

      <li><a href="">Smallmouth grunt
        </a></li>
      <li><a href="">Burrito</a></li>
      <li><a href="">Pigfish</a></li>

    </ul>
  </li>

  <li>Remoras
    <ul>
      <li><a href="">Whalesucker</a></li>

      <li><a href="">Marlinsucker</a></li>
      <li><a href="">Ceylonese remora</a></li>
      <li><a href="">Spearfish remora</a></li>

      <li><a href="">Slender suckerfish</a></li>
    </ul>
  </li>
</ul>

Realmente simple —HTML limpio y agradable que, como resultado es altamente accesible. Pero queremos transformarlo en una lista dinámica— el primer nivel hará una barra horizontal a partir de la cual se desplegarán los elementos del segundo nivel.

Aplicamos estilos

Para empezar, todas las listas deben ajustarse un poco —concretamente, el espaciado y el margen se hacen cero y se especifica que el tipo de marcador de la lista sea nulo:

ul {
  padding: 0;
  margin: 0;
  list-style: none;
  }

Ahora, transforamremos la lista de primer nivel en una barra de menú. Hay varios sistemas para conseguirlo, que se discuten detalladamente en otro artículo en nuestro Manual. Podemos hacer que los elementos de la lista se muestren en lína (display: inline), pero en nuestro ejemplo haremos que floten a la izquierda.

li {
  float: left;
  position: relative;
  width: 10em;
  }

La posición se ha especificado comorelativa porque queremos que la posición de los elementos del segundo nivel sean relativos a los elementos del primer nivel, y hemos especificado algo de espacio para separarlos lo suficente. El menú desplegable empieza a tomar forma.

El siguiente paso es ajustar los elementos del segundo nivel de la lista que serán la parte desplegable propiamente dicha:

li ul {
  display: none;
  position: absolute; 
  top: 1em;
  left: 0;
  }

Esto coloca los elementos del segundo nivel de forma absoluta (separándolos del flujo del HTML y poniéndolos en un espacio propio) y hace que su estado inicial sea invisible. Si sustituyes display: none con display: block, verás por qué hace falta especificar las propiedades top y left en Internet Explorer, ya que sin ellas, IE alinea las listas de segundo nivel a la derecha y arriba de su antecesor relativo, en lugar de abajo a la izquierda. Por desgracia, este arreglo en IE altera las cosas en otros navegadores, como Opera, así que añade este CSS para restaurar el valor correcto para las propiedades de distancia arriba y a la izquierda en los demás navegadores que no sean IE:

li > ul {
	top: auto;
	left: auto;
	}

Y ahora, haremos que el menú funcione. Par que el menú aparezca cuando “pasamos el ratón por encima”, añadimos simplemente esto:

li:hover ul { display: block; }

Esto indica que cualquier lista que esté anidada en un elemento de lista que tenga el cursor encima debe mostrarse.

Finalmente, ya que las listas flotan a la izquierda, el contenido debajo de ellas deben liberarse de la propiedad de flotar aplicandoles el código clear: left.

¡Espera un momento!

“¡Este maldito menú no funciona!” Oigo que exclama un 102.6% de la audiencia. Estoy hablando, como habréis supuesto, de los usuarios de Internet Explorer. Cuanto más utilices y desarrolles para navegadores como Mozilla más te das cuenta de lo patético que es Internet Explorer en lo que respecta a los estándares de la web. La pseudo-clase :hover debería funcioar con cualquier elemento, pero en IE sólo vale con los enlaces. Entonces, ¿para qué sirve un emnú desplegable que va a funcionar en un -2.6% de los navegadores?of browsers? No gran cosa, honestamente. Necesitamos aplicar algo de magia.

Script basado en el DOM al rescate

Hemos indicado la falta de soporte de IE para la pseudo-clase :hover, pero empleando el DOM , podemos añadir eventos tipo mouseover y mouseout a cualquier elemento. Buenas noticias para nosotros, porque esto significa que con un simple trocito de JavaScript podemos resolver los problemas de IE con :hover

Como IE está ciego debemos encontrar una forma alternativa de identificar las propiedades de la pseudo-clase :hover . Con JavaScript, sabemos que podemos manipular la propiedad className así que primero cambiaremos el CSS:

li:hover ul{ display: block; }

becomes:

li:hover ul, li.over ul{ display: block; }

Ahora invocaremos la regla de CSS para :hover añadiendo la clase over al elemento deseado. Necesitaremos también indicar a IE cual de los elementos de la lista UL realmente debe formar parte del menú desplegable. Podemos hacerlo asignando un identificador id al elemento raíz ul:

<ul>

becomes:

<ul id="nav">

Ya tenemos una forma de identificar el elemento raíz ulde la lista desplegable, podemos tomar este elemento y pasarlo a través de todos los descendientes, añadiendo los eventos de movimiento del ratón, mouseover and mouseout events a todos los elementos anidados li:

startList = function() {
if (document.all&&document.getElementById) {
navRoot = document.getElementById("nav");
for (i=0; i<navRoot.childNodes.length; i++) {
node = navRoot.childNodes[i];
if (node.nodeName=="LI") {
node.onmouseover=function() {
this.className+=" over";
  }
  node.onmouseout=function() {
  this.className=this.className.replace(" over", "");
   }
   }
  }
 }
}
window.onload=startList;

Al cargar la página, la función startList se ejecuta. La función determina si el navegador es realmente IE5 o posterior comprobando la existencia del objeto document.all y la función document.getElementById. Es una forma un poco basta de hacerlo, pero es breve y simple y ya que queremos una solución compacta, ya irá bien. Entonces a modo de bucle hará que los eventos mouseover and mouseout vayan pasando a los elementos gracias a las claseover de la propiedad className del elemento.

Aquí está. Si te has perdido, fíjate en el ejemplo comentado, simple, en acción.

Agallas, espinas, escamas...

Hasta ahora las cosas están un poco desnudas. La idea era mostrar cómo funciona en esencia el “Suckerfish Dropdown”, pero con CSS podemos hacer que las cosas luzcan más, y quede más agradable. Un punto de partida obvio es aplicar un color de fondo a los elementos de segundo nivel.

Después de arreglar las propiedades de posición respecto de arriba y la izquierda, como se describió antes, los ejemplos del ejemplo adornado aparecen directamente debajo de los ítems del menú en la mayoría de navegadores modernos, pero desgraciadamente no en todos. En Safari 1.0, todavía cuelgan de la parte izquierda de la pantalla. {Consulta el foro de discusión para ver soluciones al problema. –Ed.}

Accesibilidad y usabilidad

Hacer enlaces a partir del primer nivel de una lista hará que los enlaces puedan seguirse con el tabulador por parte de los lectores que no utilizan ratón.

Más sobre menús desplegables

En otro artículo continuamos explicando más opciones para este tipo de menús, en este caso se trata de menús que se despliegan horizontalmente.

Dan Webb es un desarrollador web y DJ en ciernes. Su trabajo reciente incluye implementar sitios basados en estándares y accesibles para agencias del gobierno del Reino Unido, y hacer bailar a la gente en oscuros bares de Londres.

Patrick Griffiths es un desarrollador web freelance en Londres, que tiene especial predilección por la música soul music, la evolución y mantener su sitio, HTML Dog. A veces prefiere el sobrenombre PTG, según el humor del día.

[ Este artículo ha sido traducido con permiso de A List Apart y su autor.]