A 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
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.
necesito como insetar ese menu acordeon por favor
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
@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.
hola me parece estupendo el trabajo que haces,pero donde pongo el click
@susi No sé a que te refieres con lo de poner el click, si puedes ser más específica mejor.
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.
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!
@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.
Funciono, muchas gracias master!
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
@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.
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…
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.
perdón, la segunda imagen es esta:
http://img690.imageshack.us/img690/153/93892230.png
@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.
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.
@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á.
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.
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
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!
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!! 😀
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!!!
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
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
@dario Muy fácil: en la parte del javascript donde pone
.click(function(event){...
, sustituir ese.click
por.mouseover
. Feliz año a todos 🙂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
@daniel Como puedes ver en la demo, funciona, debe faltarte algo. Así sin darme más datos no sé que te puede fallar.
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^^
@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 elul
,li
,a
o en todos.Gracias David…
me quedo de lujo!
¡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.
@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.
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.
@Maicro Gracias, hombre 🙂 Ya te comento por email.
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.
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.
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.
@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.
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
@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.
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
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!
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?
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.
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!
@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().
muchas gracias!!!
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!
@Alejandro No sé que problema puedes tener, el tutorial está paso a paso.