Menú vertical en acordeón con CSS y jquery

menu_acordeonA pesar del buen feedback recibido sobre mi serie de tutoriales de CodeIgniter, los artículos sobre menús animados con CSS y javascript siguen siendo los más populares en este sitio, y parece que son bastante útiles para la gente que está empezando. Por ello hoy me tomo un pequeño respiro de los videotutoriales y voy a enseñaros cómo hacer el clásico menú vertical en acordeón con CSS y jQuery.
El resultado lo puedes ver aquí: Ver demo

HTML

Para el html del menú vamos a emplear la estructura típica de listas anidadas. La última entrada será un enlace directo, sin submenú:

<ul id="menu">
<li><a href="#">Menu 1</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>
<li><a href="#">Menu 2</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>
<li><a href="#">Menu 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>
<li><a href="#">Menu sin submenu</a></li>
</ul>

Añadiendo el CSS

Para dar estilo al menú tenemos primero que quitar los estilos por defecto de las listas, eliminar los bullets y márgenes y añadirle display:block para que queden perfectamente alineados los elementos uno debajo de otro. Después tenemos que ocultar con display:none los submenús para que aparezcan todos colapsados por defecto. Vamos a añadir algunas extensiones de CSS3 para mejorar visualmente nuestro menú. Estás extensiones sólo serán visibles en navegadores modernos (Firefox, Chrome y Safari), pero no en Internet Explorer. De esta manera podemos añadir bordes redondeados y sombras al menú y al texto. La propiedad -webkit-transition solo funciona en navegadores basados en webkit (Safari y Chrome), y la utilizaremos para mejor el hover añadiendo un fundido en el color del texto y el background. En los navegadores que no soporten estas propiedades simplemente veremos el menú con esquinas normales, hover típico on-off de CSS y sin sombras.

#menu{
	-moz-border-radius:5px;
	-webkit-border-radius:5px;
	border-radius:5px;
	-webkit-box-shadow:1px 1px 3px #888;
	-moz-box-shadow:1px 1px 3px #888;
}
#menu li{border-bottom:1px solid #FFF;}
#menu ul li, #menu li:last-child{border:none}	
a{
	display:block;
	color:#FFF;
	text-decoration:none;
	font-family:'Helvetica', Arial, sans-serif;
	font-size:13px;
	padding:3px 5px;
	text-shadow:1px 1px 1px #325179;
}
#menu a:hover{
	color:#F9B855;
	-webkit-transition: color 0.2s linear;
}
#menu ul a{background-color:#6594D1;}
#menu ul a:hover{
	background-color:#FFF;
	color:#2961A9;
	text-shadow:none;
	-webkit-transition: color, background-color 0.2s linear;
}
ul{
	display:block;
	background-color:#2961A9;
	margin:0;
	padding:0;
	width:130px;
	list-style:none;
}
#menu ul{background-color:#6594D1;}
#menu li ul {display:none;}

Añadiendo la funcionalidad con jQuery

Ahora vamos a ver lo sencillo que es hacer funcionar nuestro menú vertical. Primero añadimos el evento click a cada enlace del menú. Después comprobamos si el siguiente elemento tras el enlace es un ul, ya que si es así este contendrá un submenú, si no será un elemento de un submenú o bien un elemento principal que no contiene submenú (en nuestro ejemplo, el último enlace). Si contiene un submenú, al hacer click este se expandirá o colapsará (slideToggle()), a la vez que colapsaremos el submenú que esté visible que no sea el actual. La función event.preventDefault() sirve para evitar que cuando hagamos click el navegador siga el enlace del href tras ejecutar nuestra función javascript.

<script type="text/javascript" charset="utf-8">
$(function(){
	$('#menu li a').click(function(event){
		var elem = $(this).next();
		if(elem.is('ul')){
			event.preventDefault();
			$('#menu ul:visible').not(elem).slideUp();
			elem.slideToggle();
		}
	});
});
</script>

Podéis escribir en los comentarios cualquier duda que tengáis e intentaré responderla, así como sugerencias para próximos tutoriales.

Actualización: Ante la cantidad de peticiones de cómo hacer que el menú sea multinivel, decidí convertirlo en un plugin de jQuery y hacer un pequeño tutorial con screencast incluido: Cómo hacer un plugin jQuery – Menú acordeón multinivel

Enlaces

183 comentarios para “Menú vertical en acordeón con CSS y jquery”

  1. flaca dice:

    necesito crear un menu tipo acordion de tre niveles, por ejemplo
    casa1
    casa 1.1
    casa 1.2
    casa 1.2.1
    casa 1.2.2
    casa 1.3
    casa2
    casa3

    se los agradecere muchisimo.

  2. carlos dice:

    necesito como insetar ese menu acordeon por favor

  3. mary dice:

    Hola, muy bueno el tutorial.
    Solo me gustaría saber como o qué le añado si quiero que al darle click a uno de los vinculos (submenu 1 por ejemplo) se mantenga desplegado y seleccionado. Me seria de muchisima ayuda pudieras publicar algo sobre eso. Thnxs

  4. David Rojas dice:

    @flaca Eso sería ya para ponerlo en otro artículo.

    @carlos Es sencillo, solo sigue el tutorial 🙂

    @mary Cuando haces click en un vínculo vas a una página nueva, por lo tanto aquí el javascript no puede hacer por sí solo lo que dices, lo que deberías es en el php o lenguaje de servidor que uses hacer que se añada una clase «activo» o como quieras llamarle al vínculo correspondiente a la url que se ha cargado, y después ya añadir al css lo que quieras a esa clase. Aquí depende de cómo estés haciendo tu web y qué estés usando. Por ejemplo wordpress añade automáticamente una clase al elemento html del menú que se encuentra activo.

  5. susi dice:

    hola me parece estupendo el trabajo que haces,pero donde pongo el click

  6. David Rojas dice:

    @susi No sé a que te refieres con lo de poner el click, si puedes ser más específica mejor.

  7. susi dice:

    perdona por haberte molestado pero estoy empezando y creia que las explicaciones las tenia que cambiar yo en el codigo pero ya he conseguido que funcione.MUCHAS GRACIAS.

  8. Gonzalo dice:

    Buen día David, primero quiero felicitarte por lo sencillo y útil que lograste crear el menú (aunque el JS es una locura jeje).

    Mi duda es la siguiente, como puedo lograr que al cargar la página uno de los «li» este desplegado?

    He intentado varias formas pero la verdad es que ya me sobrepaso.

    Muchas gracias!

  9. David Rojas dice:

    @Gonzalo Pues añadiendo una clase o un estilo inline al ul que haya dentro de ese li. La manera más facil: pon <ul style=»display:block»> en el <ul> que quieras que esté desplegado.

  10. Gonzalo dice:

    Funciono, muchas gracias master!

  11. DoctorPC dice:

    Hola, sabes? el menú se me ve así:
    http://img101.imageshack.us/img101/5867/111d.png

    Definitivamente es el Explorer (ie8)?
    alguna solución :S

    Muchas Gracias

  12. David Rojas dice:

    @DoctorPC Los borders redondeados y sombras no los soporta Internet Explorer, pero no sé porqué el color de fondo de los submenús no cambia. Le echaré un vistazo.

  13. DoctorPC dice:

    Gracias @David, pero creo que algo estoy haciendo mal, porque como sale en la imagen, sólo se ve una linea vertical de menus sin ningun efecto de acordeón…

  14. DoctorPC dice:

    Bueno ya hice que funcionara (copie y pegue el código del demo y me faltaba la invocación 😛 del script ajax) así que dejo el feedback para los que pasen.

    Mi duda es la siguiente:
    Tengo otra hoja de estilo X que ya tiene las características definidas de UL.
    Al agregar la css tuya, deforma los elementos UL de mi CSS actual.

    Traté de colocar la UL del ejemplo con otra ID y también como clase dentro de la css para llamarla despues en el html pero
    simplemente no me tomó… (esto para diferenciar los UL, y que tome las características por separado).

    Te dejo las pantallas a ver si me puedes hechar una mano:

    Acá estoy tratando de agregarle un id

    http://img263.imageshack.us/img263/766/91487408.jpg

    Este es el resultado:

    Con una class pasa lo mismo, ¿cómo puedo arreglar este inconveniente?

    Nuevamente muchas Gracias 🙂

    PD: efectivamente con ie8 no se ven los bordes redondeados.

  15. David Rojas dice:

    @DoctorPC No veo el resultado, copiaste la misma url dos veces en el comentario (he borrado una). De todas formas, no sé si tienes claros los conceptos de cómo funcionan las hojas de estilo. En la captura que me pones, la regla #aco ul { … }, eso se dirige a todos los ul que tengan como padre («ancestro» en realidad) un elemento con id #aco (en tu ejemplo, ninguno). Para estilar el elemento ul de id #aco puedes hacer ul#aco { … } o simplemente #aco { … }. También ten en cuenta que los ids en una página deben ser únicos.

  16. Jose dice:

    Primero que nada dejame felicitarte por tu minitutorial que es genial, pues da mucha presentacion este efectito.
    Bueno quiero utilizar un widget de jquery que se llama accordion para poner dentro funciones basicas de base de datos como altas, basjas, etc., ¿Como puedo utilizarlo?, porque cuando lo llamo en mi html no me muestra la estructura que deberia ser, a y claro utilizando CI además soy principiante en este framework que es muy bueno por cierto.
    Esperando tu respuesta saludos y una vez mas muchas felicitaciones.

  17. David Rojas dice:

    @Jose Según veo en la documentación del plugin de accordion es bastante sencillo de utilizar, échale un vistazo, aunque esté en inglés se entiende, realmente sólo es una línea de javascript, siempre que la estructura de tu html sea como dicen ahí. Ten en cuenta de que además de jQuery y el plugin, tienes que cargar jQuery UI, ya que este plugin tiene esa dependencia, si no no funcionará.

  18. Jose dice:

    Hola de nuevo, primero gracias por tu pronta respuesta, y tenias razon, lo que me hacia falta era leer un poco más xq si me hacia falta un js, ja ja, bueno en fin como sea ya me quedo gracias.
    Ahora tengo otro problema, en mi vista de alta tengo 2 combos select que muestran opciones de un catalogo de mi base de datos, y cuando meto mi vista dentro del div del accordion ya no me muestra el contenido de mis combos, estan en ceros, como puedo hacerle para que me los muestre?
    bueno gracias por todo y espero me puedas ayudar, ja es la primera vez que pido ayuda en este tipo de sitios y es muy buena, sale adiosin.

  19. Jose dice:

    Hola Hola otra vez, que crees ya resolví mi problema, lo que tenia mal es que las variables que mandaba de mi combo los direcionaba a la pagina que tenia cuando los cree y solo tenia que mandarlos en la pagina que ahora los estaba cargando y ya, bueno saludos y si tengo otra duda no dudare (valga la rebusnancia) en solicitar de tus conocimientos, sale adiosin

  20. DoctorPC dice:

    Mi estimado gurú del css 🙂
    Espero con ansias el segundo tutorial del menú acordeon con jquery que mencionaba @Flaca.

    menu padre
    menu hijo
    menu nieto
    menu padre
    menu hijo
    menu padre

    Saludos!

  21. Amiantum dice:

    Buenas!

    Genial blog, llegué hace unos días a él buscando cómo hacer menús desplegables y me pareció genial este post, muchas gracias!!

    Estoy intentando hacer lo que también ha comentado @Gonzalo, hacer que una de las listas anidadas aparezca desplegada pero no hay con la solución que le has dado ()

    De hecho, lo que quiero es que el menú deje de ser dinámico y sólo pueda verse desplegado. He dejado de usar el javascript pero, como digo, no hay forma de que las ul aparezcan desplegadas por defecto. Lo estoy intentando con un estilo inline en ul así que el css de tu tutorial está intacto.

    Si se os ocurre algo que me pueda ayudar os lo agradecería.

    En cualquier caso, muchas gracias!! 😀

  22. Amiantum dice:

    Pues creo que me voy a responder yo solito, el ul que quiero desplegar lo he dejado tal cual, sin estilo inline, y en el CSS, la ultima linea la he modificado:

    #desplegable li ul {display:block;}

    y alehop!!

    Muchas gracias!!!

  23. reispab dice:

    lo que no entendemos los novatos es que estos hablan muy por enseima de nuestro nivel y no comprendemos muchas cosas. como hacer desplegable el menu y como deve quedar al final se les olvido una imagencita

  24. dario dice:

    hola david, mi pregunta es si se puede hacer que el submenu se despliegue no con un click sino cuando paso con el mouse. se puede? como seria?
    desde ya muchas gracias y feliz año

  25. David Rojas dice:

    @dario Muy fácil: en la parte del javascript donde pone .click(function(event){..., sustituir ese .click por .mouseover. Feliz año a todos 🙂

  26. daniel dice:

    Se ve muy genial el Menú…

    pero no me funciona… copie el codigo tal cual esta en una sola pagina … pero el menu no se despliega para que se vean los contenidos.. lo probe en ie y en firefox.. y pasa lo mismo en los 2

    q podria estar pasando con el codigo?

    Gracias

  27. David Rojas dice:

    @daniel Como puedes ver en la demo, funciona, debe faltarte algo. Así sin darme más datos no sé que te puede fallar.

  28. daniel dice:

    uhh.. si .. sorry.. fue una omision tonta de mi parte!

    funciona de maravillas… Gracias!

    aprovexando tu pronta respuesta :p

    como hago para dejarlo transparente… es q tengo una imagen q no kiero q se tape abajo del menu… es posible dejar transparente el menu ?

    Gracias^^

  29. David Rojas dice:

    @daniel No sé si te refieres a que el background del menú sea transparente. Si es así en el css tienes que poner background-color: transparent en los elementos cuyo fondo quieres que sea transparente. Todo depende de cómo haya estilado el menú, tal vez tengas que ponerlo en el ul, li, a o en todos.

  30. daniel dice:

    Gracias David…

    me quedo de lujo!

  31. Maicro dice:

    ¡Dios! David, de verdad, eres un maldito genio.

    He combinado este menú con el anterior que pusiste y ha quedado genial.

    Oye, cosas como estas son maravillosas y, personalmente, me gusta agradecerlas. Aunque, como ya te dije, la página la estoy haciendo para un amigo sin cobrarle, de no ser por ti, no habría sido nada funcional. ¿No tienes alguna cuenta de PayPal donde poder hacerte una donación? Yo es que de libros en Amazon, como que no, y Alicante me pilla muy lejos para invitarte a café 😉 En serio, tío, no creo que seas consciente del favor que me has hecho dándome a conocer todo esto para hacerle la página a mi amigo.

    Un abrazo.

  32. David Rojas dice:

    @Maicro Muchas gracias, da gusto ver que todo esto le es útil a la gente. Tengo cuenta personal de paypal (la dirección es la misma que el email que tengo en la página de contacto), pero al no ser cuenta premier no puedo poner un botón de aceptar donaciones, sólo se me puede transferir dinero desde otra cuenta paypal. La verdad es que no me había planteado poner un botón de estos, puse el link de Amazon por si alguien quería agradecerme algo, aunque tampoco pensé que nadie fuera a utilizarlo (los libros son caros). El dinero va y viene, pero un libro siempre lo tienes ahí y te acuerdas de quién o porqué te lo regalaron.
    Pues nada, te animo a que te sigas pasando por mi blog, comentando, preguntando lo que quieras. Enséñanos la web que estás haciendo si te apetece. A veces recibo bastantes visitas pero pocos comentarios, entonces no sé si realmente mis artículos están ayudando a alguien.

  33. Maicro dice:

    De nada, por dios. Gracias a ti.

    Bueno, pues ahora me paso por PayPal. Así te pillas el libro que tú quieras 😉

    Eso dalo por hecho. Seguiré viendo las maravillas que muestras.

    De momento, no quiero hacer pública la página de mi amigo hasta que no solucione los problemas que Arsys me está poniendo para redireccionar los dominios de mi colega -¡qué horror de ISP!-. Pero vamos, si quieres verla, añade a mi dominio classicco 😉 La opción de menú de navegación que combina ambos tutoriales es DESARROLLOS. Que, por cierto, metí la pata a la hora de validar, pero ya lo solucioné.

    Lo dicho, muchas gracias.

  34. David Rojas dice:

    @Maicro Gracias, hombre 🙂 Ya te comento por email.

  35. Jose dice:

    Que tal, otra vez molestando, aunque ahora no es nada referente a los menus que muestras aqui, pero de igual manera espero que me puedas ayudar, pasa que en el sistema que estoy haciendo requiero de inserciones a base de datos en oracle, inserta de maravilla, mi problema es que cuando intento meter acentos y/o eñes me pinta caracteres extaños que no son lo que yo inserto, en otro lado dicen que solo tengo que cambiar la codificacion utf8 por latin 1, pero eso tampoco funciona, bueno en espera de tu rponta respuesta y ojala puedas ayudarme me despido que estes bien y ademas felicitarte por tus entradas que estan muy bien explicadas. sale Adiosin.

  36. Jose dice:

    hola de nuevo, que cres que ya resolvimos el problema de los acentos y eñes en codeigniter y oracle bueno gracias de todos modos y cualquier cosa enserio que no dudare en preguntarte, bueno Adiosin.

  37. René dice:

    Estimado.
    he estado viendo vuestra ayuda del Acordeon…
    estoy haciendo un sistema en el cual hago menu con efecto accordion en PHP…
    la cosa es que todo me funciona perfecto pero dentro de cada menu, hay un formulario y dentro de ese form, un , la cosa es que cuando cargo la pagina, el select no me muestra la info… es decir, me esta mostrando la variable, cabe decir que dicho select, se alimenta de una consulta a BD de SQL Server, y mi conexion la hago con PDO.
    alguna ayuda con eso, seria genial.
    gracias y saludos.

  38. David Rojas dice:

    @René me temo que no entiendo cuál es el problema que tienes, quizá si te explicas mejor o pones una url con la demo te puedo echar una mano.

  39. René dice:

    el menu despegable del acordeon, es asi:

    cliente: (campo hecho con un select)
    datos:(cuadro de texto)
    fecha:(cuadro de texto)
    los cuadros de texto se llenan automaticamente con informacion de una consulta a SQL, el select del cliente, debiera desplegar una lista con los clientes, la cual se alimenta de una consulta sql, si lo hago fuera del accordion, funciona, pero al ponerlo dentro del acoordion, me aparece el nombre de la variable..
    por ejemplo:
    echo»»;
    $sql = «select cliente from clientes»;
    include (‘conexion a BD’);
    $consulta = $link->prepare($sql);
    $consulta->execute();
    while ($row = $consulta->fetch())
    {
    echo»».$Row[0].»»;
    }
    «»;
    $link = null;
    $consulta = null;

    esa parte del codigo cuando lo ingreso al accordion, se pierde y aparece en vez de los datos de la consulta, la variable $Row[0], se entiende ahora.?

    espero haber sido mas claro, gracias y saludos

  40. David Rojas dice:

    @René Lo que comentas no tiene mucha lógica. El hecho de meter el javascript del acordeón (o el css) nunca puede causarte un error de php. Revisa bien el código porque en algún sitio se te han colado unas comillas o algún tag de <?php por abrir o cerrar.

  41. René dice:

    gracias estimado…
    pero ya lo resolvi…
    al final hice la consulta sql fuera del accordion y el resultado lo guarde en un array, dentro del accordion puse el array en un select.
    quedo impecable.
    gracias

  42. jnoir dice:

    Genial las indicaciones, me han servido de gran ayuda. Mi pregunta sería, ¿cómo hacer que los enlaces de los menus padres («Menu 1», «Menu 2», etc) carguen contenido siguiendo la etiqueta a? No soy experto en javascript ni JQuery, pero sospecho que el hecho de usar el evento .click para desplegar el menu hace que no use el método «standard» para cargar el enlace. No he hecho aún la prueba de cambiar este método .click por un .mouseover o algo así, para verificar. ¿Podrías darme alguna sugerencia? No tengo muy claro si debo añadir un nuevo método .load() o .post() o si en realidad hay alguna forma más sencilla de hacerlo que esté pasando por alto…

    Muchas gracias por la información y, sobre todo, por el seguimiento!

  43. jnoir dice:

    Perdon por el comentario de antes, he incluido una etiqueta pensando que la pondría como texto… la frase sería:

    ¿Cómo hacer que los enlaces de los menus padres («Menu 1», «Menu 2», etc) carguen contenido siguiendo la etiqueta «a» de html?

  44. jnoir dice:

    Pidiendo disculpas por el «flood» de comentarios y continuando con el tema… efectivamente tienen que ir por ahí los tiros, al cambiar el evento para desplegar el menu de .click() a .mouseover() la etiqueta «a» de HTML se aplica y el contenido se carga. Así que debo investigar una alternativa… Iré probando con .load() o .post(), pero agradecería saber si hay una forma más elegante de proceder.

  45. Marcos dice:

    Hola, muy útil el tutorial, me ha ayudado bastante para entender como hacer menús desplegables pero tengo un problema…

    La demo que tienes para probar el menú me funciona perfectamente tanto en Firefox como en IE(v8.0), sin embargo cuando trato de hacerlo yo el menú no se me despliega (ni en uno ni en otro explorador); imagino que debe ser por el Javascript pero no sé a qué se debe.

    He probado a mirar el código fuente de tu ejemplo y añadir la línea:
    ajax.googlepis.com/ajax/libs/jquery…

    Aún así tampoco…¿Alguna idea?

    Gracias de antemano!

  46. David Rojas dice:

    @Marcos Te recomiendo instalar FireBug para Firefox y así comprobarás en la consola si te da algún error. Si no lo encuentras, pon alguna url con el ejemplo.
    @jnoir El script carga la página a la que apunta el enlace siempre que éste no contenga submenús (si los contiene, se debe desplegar). Si lo que quieres es cargar algo por ajax efectivamente la manera más fácil es usar el método .load().

  47. Armando dice:

    muchas gracias!!!

  48. Alejandro dice:

    Hola, muy bueno! La verdad que estoy aprendiendo sobre esto, cree mi menu en el codigo html, copie el estilo en mi .css, pero no entendi la parte del script, la pego entre las etiquetas head y nada, me quede ahi, no se donde poner, ni como el script para que funcione, espero tu respuesta, desde ya muchas gracias!

  49. David Rojas dice:

    @Alejandro No sé que problema puedes tener, el tutorial está paso a paso.

Deja un comentario

Time limit is exhausted. Please reload the CAPTCHA.

RSS iTunes podcast Twitter

Categorías

Enlaces

Archivos