Tras el inesperado éxito de mi artículo Menú animado con CSS y jquery, me he decidido a escribir un nuevo tutorial sobre creación de menús: cómo hacer un menú horizontal animado desplegable con CSS y jquery. Cada elemento del menú horizontal contendrá un submenú vertical que se desplegará con una animación. A su vez, al pasar el ratón sobre cada entrada del submenú éste cambiará de color de forma gradual. El resultado lo puedes ver aquí: Ver demo
Imágenes
La única imagen que vamos a utilizar es este gradiente para el fondo de los submenús, que además del efecto relieve que proporciona, nos ayudará a realizar las transiciones del hover.
HTML
El html empleado es una simple lista con otra lista anidada para cada submenú:
<ul id="nav"> <li><a href="#">Menu 1</a> <ul class="submenu"> <li><a href="#">Submenu 1</a></li> <li><a href="#">Submenu 2</a></li> <li><a href="#">Submenu 3</a></li> </ul> </li> <li><a href="#">Menu 2</a> <ul class="submenu"> <li><a href="#">Submenu 1</a></li> <li><a href="#">Submenu 2</a></li> <li><a href="#">Submenu 3</a></li> </ul> </li> <li><a href="#">Menu 3</a> <ul class="submenu"> <li><a href="#">Submenu 1</a></li> <li><a href="#">Submenu 2</a></li> <li><a href="#">Submenu 3</a></li> </ul> </li> <li><a href="#">Menu 4</a> <ul class="submenu"> <li><a href="#">Submenu 1</a></li> <li><a href="#">Submenu 2</a></li> <li><a href="#">Submenu 3</a></li> </ul> </li> </ul> |
Añadiendo el CSS
La mayor parte del css son para mejorar el aspecto visual del menú. Funcionalmente, podemos destacar varias cosas. Los elementos de la lista principal (#nav) se encuentran flotados a la izquierda, para formar el menú horizontal, y tienen position: relative para que sirva de referencia a cada submenú. A la lista del submenú le asignamos position: absolute, para que cuando se despliegue esté situada bajo su menú correspondiente. Este submenú lo ocultamos por defecto con display: none para después mostrarlo con javascript cuando pasemos el ratón por encima de su menú padre. A cada enlace del elemento del submenú añadiremos la imagen del gradiente como background.
a{ display: block; text-decoration: none; color: #004a80; padding: 5px; } ul{ width: 500px; height: 28px; } ul,li{ list-style: none; margin:0; padding:0; } #nav{ font-family: 'Century Gothic', sans-serif; } #nav li{ float:left; position: relative; width: 125px; font-size: 14px; font-variant: small-caps; border-top:1px solid #004a80; border-bottom:1px solid #004A80; } .submenu{ display: none; position: absolute; left: -1px; border:none; height: auto; background: none; } #nav .submenu li{ float: none; position: static; margin: 0; font-size: 11px; font-variant: normal; border: 1px solid #004a80; border-top: none; width: 124px; } #nav .submenu li a{ color: #FFFFFF; background: #004a80 url('fondo_menu_vertical.png') repeat-x 0 0; width: 114px; height: 16px; } |
Javascript y jQuery
Ahora añadiremos la funcionalidad del menú. Para ello necesitaremos primero incluir la librería jQuery, que podemos hacerlo cargándola directamente desde el repositorio de Google:
<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.3/jquery.min.js" type="text/javascript" charset="utf-8"></script> |
También necesitaremos añadir el plugin backgroundPosition para jQuery, ya que éste no soporta de serie la animación de la propiedad background-position. Lo descargaremos y añadiremos así:
<script type="text/javascript" src="jquery.backgroundPosition.js"></script> |
Finalmente, con unas pocas líneas de código, usando la función slideDown/slideUp y el evento hover mostraremos el submenú correspondiente cuando pasemos el ratón por uno de los elementos del menú principal. Usando la función animate, al pasar el ratón por encima de cada entrada del submenú se cambiará la propiedad background-position, deslizando la imagen del gradiente y creando un efecto de fundido rápido, para que la transición sea más suave que si utilizáramos simplemente a:hover para cambiar el color de fondo del enlace activo.
<script type="text/javascript"> $(function(){ $('#nav>li').hover( function(){ $('.submenu',this).stop(true,true).slideDown('fast'); }, function(){ $('.submenu',this).slideUp('fast'); } ); $('.submenu li a').css( {backgroundPosition: "0px 0px"} ).hover( function(){ $(this).stop().animate({backgroundPosition: "(0px -99px)"}, 250); }, function(){ $(this).stop().animate({backgroundPosition: "(0px 0px)"}, 250); } ); }); </script> |
Hola David, muy interesante este código.
Cómo puedo añadir una imagen distinta a cada link que se abra/cierre al pasar el ratón por cada uno de ellos.
Quiero crear un menú parecido con mis enlaces a páginas deseadas, algunas de estas páginas no las visito muy a menudo y no sé de que van, entonces al mostrarme una imagen es más fácil recordar de que va esa página.
No sé si me explico pero como en tu página aparecen popup en algunos enlaces haber si se puede mostrar una imagen distinta en cada link.
Gracias.
@laszarzitas Supongo que te refieres a los popup de infolinks, esto son publicidad simplemente. Si quieres hacer un efecto parecido y que muestre un previo de la url a la que apuntas al pasar el ratón, puedes usar por ejemplo este plugin de jQuery:
http://cssglobe.com/post/1695/easiest-tooltip-and-image-preview-using-jquery
En el ejemplo 3 ‘Links With URL Preview’ te explica cómo usarlo para lo que quieres. Échale un vistazo a la demo:
http://cssglobe.com/lab/tooltip/03/
Gracias David Rojas.
He estado unos días de vacaciones, he probado tus consejos y funcionan perfectamente.
De nuevo gracias.
Hola David. Muchas gracias por el tutorial.
Quería preguntarte cómo podría hacer para que los items del menu desplieguen su información al hacer click en ellos y no al apoyarse arriba.
Gracias nuevamente,
Paul
@Paul Pues puedes sustituir el método .hover por el .click, y añadir una clase para indicar si el elemento está abierto. Cambia el bloque de $(‘#nav>li’).hover(… por este otro:
$('#nav>li').click(function(){
if($('.submenu',this).hasClass('abierto'))
$('.submenu',this).slideUp('fast').removeClass('abierto');
else{
$('.abierto').slideUp('fast').removeClass('abierto');
$('.submenu',this).stop(true,true).slideDown('fast').
addClass('abierto');
}
}
);
Habrá otras formas más elegantes, esta es la primera que se me ha ocurrido. A partir de ahí ya lo tuneas a tu gusto 🙂
Muchas gracias David!
Igualmente, por algún motivo no me está funcionando el código. El dreamweaver me tira un error de sintáxis que no logro descubrir qué es… copio acá el código que reemplazé:
$(‘#nav>li’).click(function(){
if($(‘.submenu’,this).hasClass(‘abierto’)){
$(‘.submenu’,this).slideUp(‘fast’).removeClass(‘abierto’);
}else{
$(‘.abierto’).slideUp(‘fast’).removeClass(‘abierto’);
$(‘.submenu’,this).stop(true,true).slideDown(‘fast’).addClass(‘abierto’);
}
}
}
Ya lo solucioné, era una estupidez. Había que cerrar el código con
}
});
Gracias, tema resuelto!
Gracias amigo, una pregunta como hago esos efectos cuando paso el puntero sobre el link se mueve hacia la derecha y cuando pongo el puntero sobre tu nombre como hago para que realice ese efecto, muchas gracias espero tu respues amigo.
@Jeyson Cuando dices poner el puntero sobre mi nombre, supongo que te refieres al efecto del logo de la cabecera de la página, es el mismo efecto que en el menú, lo expliqué en el otro artículo: Menú animado con CSS y jquery
Sobre los links que se mueven a la derecha, simplemente:
$('div#navegacion a, div#conecta a').hover(function() {
$(this).stop().animate({ marginLeft: '5px' }, 200);
},
function() {
$(this).stop().animate({ marginLeft: 0 }, 200);
});
Siendo div#navegacion a, etc, los links que quieras animar. Como ves es muy sencillo, solo tienes que animar la propiedad margin-left y añadirle unos pixels de margen cuando se dispare el evento hover.
Hola David, te agradezco por este tutorial en realidad fue de mucha ayuda para mi web, pero tengo un inconveniente, el menu me salio de maravillla solo que este se despliega debajo de las imagenes que realice con cicle de JQUERY, y bueno la idea es que se despliegue superpuesta a todo objeto…su tuvieras alguna idea de como solucionar este detalle te agradeceria muchisimo
@Jose Agustin: No sé tu caso en concreto, pero prueba a ponerle z-index:2 por ejemplo en el CSS del bloque se te despliega por debajo (el ul del menú), debería arreglarlo.
Hola David, intente con el z-index que me dijiste pero aun no consigo una solucion concreta y bueno el cicle de jQUERY que use esta debajo del menu como una pequeña animación de imagenes referente a mi web, claro esto lo hice antes de incluir la botonera y bueno cuando puse la botonera este me sale debajo de dicha animación lo ideal es que salga superpuesta….si tuvieses alguna otra idea te agradeceria mucho
@Jose Agustin Si no veo la web no sabría decirte. Probablemente sea problema de modificar también el z-index de alguno de los contenedores donde tienes la animación de imágenes, o de ponerle position:relative.
Hola David. Muchas gracias por tu tutorial. De momento, me ha servido. Digo, de momento porque ya lo he adaptado a mis necesidades. Ahora me queda poder adaptarlo al diseño de la página.
Por esto último quería hacerte una sugerencia, desde la humildad, no sea que vaya a meter la pata hasta el fondo. Verás, ¿no sería bueno meter toda la lista de HTML en un con un {class} determinado? Es que pensaba que si en la página ponemos más enlaces y/o listas no ordenadas, todos cogerían las características que le ponemos al menú. ¿Me equivoco?
Lo dicho, muchas gracias 😉
¡Vaya! disculpas, quería decir » ¿no sería bueno meter toda la lista de HTML en una capa con un {class} determinado?» 😀
Por cierto, mis nulos conocimientos en JavaScript me llevan a tener que formularte este pregunta, ya que no doy con ello.
Por favor, ¿qué debería de poner para que en un MouseOver me cambiara el fondo de cada uno de los elementos de la lista y sublista? Muchas gracias y disculpa.
@Maicro No es necesario, si te das cuenta la lista principal que contiene todo el menú ya tiene un id=»nav», lo que pasa es que en el CSS para este ejemplo he metido algunos estilos en los tags genéricos, pero con ese id puedes escribir el CSS de tal manera que solo modifiques las listas y enlaces del menú (que todas las reglas sean #nav li, #nav a, etc.).
Sobre tu pregunta del mouseover, no entiendo qué quieres hacer exactamente, en el ejemplo ya se cambia el fondo de las sublistas.
Hola David. Gracias por tu respuesta.
Lo de la capa lo decía por el CSS que hace referencia a los enlaces, a las listas no numeradas y a los elementos de las listas. Con ese CSS, ¿no afectaría a todos los elementos similares de la página?
Respecto al efecto. Entiendo que tal como está, al pasar el puntero por encima del enlace, la imagen de fondo se deslaza para dejar ver el color de fondo del elemento li. Yo lo que busco es que la imagen de fondo que le pongo al elemento li, simulando un botón apagado, se cambie, al pasar el ratón, por otra imagen de fondo de elemento li, simulando un botón encendido.
Espero haberme explicado bien, porque he escrito desde mi HTC. Muchas gracias David, y disculpa las molestias. Saludos.
@Maicro Con ese CSS sí, pero no necesitas añadir nada al html, sólo modificar el CSS simplemente haciendo la regla más específica, cambiando los
ul, li{..} por #nav ul, #nav li{...}
, etc.Si analizas el ejemplo, lo que hace es deslizar la imagen de fondo del enlace pero no deja ver el fondo del
li
, sino que al ser la imagen un gradiente se desliza de la zona más oscura a la más clara. Si quieres simplemente cambiar el fondo, utiliza el método.css()
en vez del.animate()
, y con él cambia la propiedadbackground-image
de css. Ten en cuenta también que no tienes que cambiar el fondo delli
, sino del enlace contenido en él, ya que éste tiene las mismas dimensiones (ela
ocupa todo elli
). Realmente para lo que quieres hacer, puedes utilizar simplemente el pseudo-selectora:hover
de CSS, sin necesidad de utilizar javascript: pones en el CSS a tus enlaces.submenu ul li a{ background-imagen:url('tuimagenoff.jpg') }
y después.submenu ul li a:hover{background-imagen:url('tuimagenon.jpg') }
.Espero que te sirva, si no te aclaras busca sobre a:hover en google, es muy sencillo.
Gracias, me pondré con ello. Lástima que sea de Madrid, sino, te invitaba a ese café 😉
Ahora lo pruebo y te cuento. Saludos.
Pues algo he hecho mal porque no me funfiona 🙁 Las diferencias con tu codigo de las que sea consciente son que he cambiado:
· #nav por #menu en HTML, CSS y SCRIPT.
· En el CSS, como fondo de de cada elemento de la lista, #menu li{, he definido el fondo del botón, porque deseaba que también tuviera apariencia de boton, con esta línea: background: #e1dc00 url(«img/botonoff.gif») repeat-x 0 0;
· Los tamaños de los elementos de la lista.
El resultado: http://img33.imageshack.us/img33/273/menuw.gif
No consigo resaltar los elementos con el fondo que debería de estar encendido. ¿Alguna idea? 😉
David, y resto de compañeros, os ruego me disculpéis. Uno, como buen primate antropomorfo, teniendo lo fácil y lo obvio en frente suya, es capaz de dar un rodeo tremendo para alcanzarlo.
Eso me ha pasado a mí. enfrascado en la realización de un menú que tenía en mente y encontrar esta página, he querido seguirlo fielmente. Sin darme cuenta de que lo que quería era mucho más fácil. Y lo peor, es que tú, David, me lo has dicho bien claro, en CSS con a:hover. ¡Qué idiota que soy! Todo el día pegándome para conseguir lo que tú me habías dicho. Y lo pero, la semana pasada estudié en el manual de Belén Albeza, de Demasiada Cafeína.
¡NO TENGO PERDÓN! Muchas gracias David. Creo que deberías de borrar mis absurdo mensajes anteriores, ¿no? Disculpa.
Una vez más, muchas gracias. Si vienes por Madrid, no sólo te invito a un café, sino a un almuerzo 😉 Saludos.
Hola muy bueno su ejemplo, como puedo colocar
el submenú con bordes redondeados?, existe alguna libreria de Jquery que lo haga?
Saludos
@Claudio Tienes este plugin: http://plugins.jquery.com/project/corners para ello. Aunque si no te importa que no estén redondeados en IE, puedes usar simplemnte las propiedades CSS3 de los navegadores: -webkit-border-radius y -moz-border-radius. De esta manera en Firefox, Chrome y Safari se verán redondeados, aunque en IE no, y te ahorrarás meter javascript.
Hola de nuevo, muchas gracias por la respuesta,
Tengo un nuevo problema y pasa que cuando te posicionas en el submenu y luego corres el mouse hacia el lado derecho, el submenu no vuelve a su estado original, por favor que puede ser ? Lo necesito urgente plisss…
Desde ya muchísimas gracias.
@Claudio Tienes razón, no me había dado cuenta de ese bug. Es sencillo, ocurre porque el contenedor del submenú tiene la anchura demasiado grande. Añade el mismo width del enlace del submenú (en este ejemplo 126px;) al css del ul.submenu y se arreglará.
Excelente sitio, ojala existan mas aportaciones como esta…
Ya esta es la segunda vez que paso por tu bloq, y cada vez es mas util.
sobre todo por la seccion de codeigniter de las cuales ahi pocos ejemplos en la web asi de buenos.
gracias, saludos.
Hola David. Para poder ejecutar el Menú animado con CSS y jquery es necesario estar conectado a internet, viendo el ejemplo y sin conexion a internet, los menus no activan el evento, es necesario el plugin jquery.min.js. ahora bien, todos lo ejemplo lo ejecuto sin estar conectado en internet.
@hibis Sí, se necesita estar conectado tal como está el ejemplo, ya que carga jQuery desde el CDN de google. Pero si quieres simplemente descarga jQuery en tu máquina y cambia el enlace, y ya te funcionará en local.
buen menu, aunque para mi(y en mi blog lo uso) el mejpr es el menu flotante.
Buenos días David, en primer lugar felicitarte por el blog y este artículo me parece muy interesante, me surge una duda, como se puede añadir un nivel más en el submenú?. Gracias de antemano
Un saludo
Noemí
@Noemí Si lo que quieres es algo que funcione simplemente, en vez de hacerlo tú manualmente, puedes usar el plugin de jquery superfish: http://users.tpg.com.au/j_birch/plugins/superfish/#sample1
Es justo lo que estaba buscando, mil gracias!!! Me viene genial como base 🙂
Un saludo
Noemí
Hola, creo ya te preguntaron esto, disculpa ya te hemos de tener cansado con tanta pregunta, pero no lo puedo arreglar, resulta que los submenus me salen por detras de todo lo que le ponga abajo del menu: una tabla, un iframe, una animación de flash, etc. probe la opción que das, de poner position:relative; en el css, porque la otra solución q sugieres (z-index:2) no se donde ponerla.
.submenu{
display: none;
position: relative;
left: -1px;
border:none;
height: auto;
background: none;
}
no se si hice lo correcto, pero con lo anterion, en el mozilla firefox recorreo todo el contenido despues del menu hacia abajo para desplegar los submenus, pero en internet explorer no pasa nada, sigue apareciendo detras de todo el contenido. Gracias por tu ayuda.
@Concha prueba a poner el z-index en el
#nav{ ... }
He conseguido aumentar el ancho de los submenús, y con ellos se alarga el fondo con efecto relieve. Pero detrás de la lista de submenús, hay otro fondo azul que no se alarga (será el que comentas que ‘nos ayudará a realizar las transiciones del hover’).
¿Dónde encuentro esa propiedad CSS para alargar ese fondo? ¿o pertenece a javascript?
Por más que toqueteo no doy con ello.
¡Gracias por este fantástico tutorial!
*Siento el doble-comentario*
Creo que me expliqué mal, porque no es un fondo, sino un borde. Adjunto una imagen a ver si se entiende mejor.
http://img39.imageshack.us/img39/7683/portapapeles01t.jpg
No sé como alargar ese borde para adaptarlo al nuevo ancho del submenú (que es 190px) y por eso queda ese espacio en blanco que señalo en la imagen con una flecha.
Gracias.
@Yllelder Pon un enlace al menú que estás haciendo, con una captura solo no sabría decirte. De todas formas ese tipo de errores suelen arreglarse fácilmente haciendo unas pruebas con firebug.
Hola David, gracias por tu interés.
No puedo poner un enlace porque estoy trabajando en local, no tengo la web subida a ningún sitio aún.
De todas formas, con Firebug (gracias por la recomendación) he desactivado la imagen de fondo del submenú y ahora se ve perfectamente como el borde del submenú no se alarga igual que el fondo:
http://img406.imageshack.us/img406/9564/salido.jpg
¿Me explico? :S
Vale, ya lo solucioné añadiendo una clase diferente a cada con un ancho propio.
Que tal, la verdad soy principiante en esto sin embargo me gusta mucho, mira ya usé el menu y toda la cosa, cómo puedo hacer q cargue swf sin q me lleve a otra página, no blank, self etc, sino a un lado del mismo menu, tipo como si lo llamara en un contenedor….:S heeelp! tmb quiero implementar jquery, heeeelp!! thanx!!
@Carlos Lo que quieres supongo que es cargarlo vía ajax: http://api.jquery.com/load/
Mi pregunta, mas bien problema es:
Tengo una página en php, que se comunica con sql, tiene ajax, jquery y el problema es que creo el menú tal cual aquí, obviamente cambiando las variables, id y classes, y no me funcionan las acciones, osea, no desliza el menú ni nada, solamente muestra los botones padre pero no despliega el submenu, no se, de pronto no reconozca scripts o allá otro que lo este bloqueando, alguna idea?
@Flinbu Como siempre, recomiendo usa Firebug para ver si tienes algún error en el javascript, y si no lo encuentras pon aquí la url para que le echemos un vistazo.
hola
una pregunta ¿el css va entre las estiquetas en ?
buen tuto,gracias!!!!!!!
oye el menu desplegable. se puede ampliar a 3 nuveles?
necesito uno para crear un sitio y no puedo encontrar uno ke funcione en explorer 6 y 8 a la vez
espero me puedas ayudar. saludos
@pedro Busca un plugin de jQuery llamado ‘Superfish’, que te dará más flexibilidad para lo que quieres.
Hola David, saludos a la madre patria…
Queria pedirte si puedes publicar sobre este mismo articulo, un comprimido con todos los archivos. te agradezco de antemano tu interés en mi solicitud