Lo que veremos hoy se aprovecha de todo esto para transformar un simple par de listas anidadas en un menú tipo "acordeón", esos en los que se despliegan las sub-opciones al tiempo que se pliegan las que pudieran estar previamente abiertas. Lo podéis ver funcionando al final de esta misma entrada o en este Codepen.
Todo esto que viene a continuación lo he puesto por separado para poder ir explicándolo un poco, pero se puede copiar y pegar dentro de un gadget, un trozo tras otro -en el mismo orden en que se presentan- y funcionará sin problemas.
HTML
La lista se construye con normalidad con la etiqueta ul y sucesivos li. Todo lo meteremos dentro de una caja con una clase que he llamado menujq para poder manejar el estilo de esta lista de manera independiente a otras listas comunes que pudieran existir en la misma página.
Para las sub-opciones simplemente se anidará otra lista completa dentro de un elemento li, teniendo cuidado de cerrar ese elemento tras el cierre de la lista anidada (</ul>).
Los enlaces que servirán para desplegar no pueden llevar a ningún sitio porque no cumplirían su función, así que se rellenan con un javascript:void(); y listo.
<div class="menujq"> <ul> <li><a href="javascript:void();">Opción1 desplegable</a> <ul> <li><a href="URL del enlace">Opc. 1.1</a></li> <li><a href="URL del enlace">Opc. 1.2</a></li> </ul> </li> <li><a href="javascript:void();">Opción2 desplegable</a> <ul> <li><a href="URL del enlace">Opc. 2.1</a></li> <li><a href="URL del enlace">Opc. 2.2</a></li> <li><a href="URL del enlace">Opc. 2.3</a></li> </ul> </li> <li><a href="URL del enlace">Opción3 Directa</a></li> </ul> </div>
CSS
La parte del estilo, además de servirnos para configurar los tamaños y para conseguir diferenciar con color la lista principal de las anidadas, también la hemos aprovechado para añadir unos simbolitos que diferencien si el elemento es desplegable o no. Detallado queda en los comentarios.
<style>
.menujq ul {
list-style: none;
width: 80%;
margin: 0 auto;
padding: 0;
}
.menujq a {
display: block;
padding: 10px;
border-bottom: 1px solid #fff;
background: #D25400;
color: #fff;
text-decoration: none;
font-size: 16px;
line-height: 16px;
text-transform: uppercase;
}
/* Símbolo elemento normal */
.menujq ul li a:before {
content: "\25CF\00A0 ";
width: 28px;
display: inline-block;
vertical-align: top;
}
/* Símbolo elemento desplegable cerrado */
.menujq ul li.desplegable a:before {
content: "\25BA\00A0";
}
/* Símbolo elemento desplegable abierto */
.menujq ul li.desplegable.activa a:before {
content: "\25BC\00A0 ";
}
/* Eliminar símbolos para sub-opciones */
.menujq ul li.desplegable ul li a:before,
.menujq ul li.desplegable.activa ul li a:before {
content: "";
}
/* Lista anidada inicialmente oculta */
.menujq ul ul {
display: none;
width: 100%;
}
/* Sangrado y segundo color para sub-opciones */
.menujq ul ul a {
padding-left: 20px;
background: #E77E23;
text-transform: capitalize;
}
</style>
.menujq ul {
list-style: none;
width: 80%;
margin: 0 auto;
padding: 0;
}
.menujq a {
display: block;
padding: 10px;
border-bottom: 1px solid #fff;
background: #D25400;
color: #fff;
text-decoration: none;
font-size: 16px;
line-height: 16px;
text-transform: uppercase;
}
/* Símbolo elemento normal */
.menujq ul li a:before {
content: "\25CF\00A0 ";
width: 28px;
display: inline-block;
vertical-align: top;
}
/* Símbolo elemento desplegable cerrado */
.menujq ul li.desplegable a:before {
content: "\25BA\00A0";
}
/* Símbolo elemento desplegable abierto */
.menujq ul li.desplegable.activa a:before {
content: "\25BC\00A0 ";
}
/* Eliminar símbolos para sub-opciones */
.menujq ul li.desplegable ul li a:before,
.menujq ul li.desplegable.activa ul li a:before {
content: "";
}
/* Lista anidada inicialmente oculta */
.menujq ul ul {
display: none;
width: 100%;
}
/* Sangrado y segundo color para sub-opciones */
.menujq ul ul a {
padding-left: 20px;
background: #E77E23;
text-transform: capitalize;
}
</style>
JAVASCRIPT
Y por fin el alma de todo esto, el JavaScript hilvanado con jQuery.
Básicamente lo que hace, en este orden, es:
- Buscar los elementos de lista, hijos directos de la clase menujq cuyo hijo sea una etiqueta de lista ul y añadirle una clase que he llamado desplegable. En otras palabras, localizar y marcar los elementos de lista que contienen una lista anidada dentro de ellos y que serán los únicos que se podrán desplegar.
- Controlar el clic sobre cualquier enlace dentro de las listas
- Guardar el objeto que sigue tras aquel sobre el que se ha hecho clic (comprobar)
- Limpiar todas las clases activa que se hayan podido añadir en anteriores clics...
- ...y añadírsela al elemento li que contiene el enlace sobre el que se hecho clic ahora
- Las dos últimas condiciones sirven para ver si una lista está plegada o desplegada (:visible) para añadirle el efecto de plegado (.slideUp) o desplegado (.slideDown).
<script type="text/javascript">
$(document).ready(function(){
$('.menujq > ul > li:has(ul)').addClass('desplegable');
$('.menujq > ul > li > a').click(function() {
var comprobar = $(this).next();
$('.menujq li').removeClass('activa');
$(this).closest('li').addClass('activa');
if((comprobar.is('ul')) && (comprobar.is(':visible'))) {
$(this).closest('li').removeClass('activa');
comprobar.slideUp('normal');
}
if((comprobar.is('ul')) && (!comprobar.is(':visible'))) {
$('.menujq ul ul:visible').slideUp('normal');
comprobar.slideDown('normal');
}
});
});
</script>
$(document).ready(function(){
$('.menujq > ul > li:has(ul)').addClass('desplegable');
$('.menujq > ul > li > a').click(function() {
var comprobar = $(this).next();
$('.menujq li').removeClass('activa');
$(this).closest('li').addClass('activa');
if((comprobar.is('ul')) && (comprobar.is(':visible'))) {
$(this).closest('li').removeClass('activa');
comprobar.slideUp('normal');
}
if((comprobar.is('ul')) && (!comprobar.is(':visible'))) {
$('.menujq ul ul:visible').slideUp('normal');
comprobar.slideDown('normal');
}
});
});
</script>
Y así es como quedará todo junto:
Ah, y casi se me olvida por obvio. Si queremos que esto funcione tenemos que tener la librería jQuery en nuestra plantilla. Si no es así entonces delante de todo este código o en la plantilla -si es que pensamos usarla para otros asuntos futuros- antes del cierre </head> tendremos que insertar esto:
<script src="http://ajax.googleapis.com/ajax/libs/jquery/1/jquery.min.js" type="text/javascript"></script>
¿Vemos otro post al azar por si le encuentras utilidad o quizás prefieres ser más metódico y suscribirte a nuestras entradas por correo? También puedes imprimir este artículo y por supuesto compartirlo en redes sociales si fue de tu agrado.
Muy interesante el post Oloman. De seguro a más de uno esto le va caer como anillo al dedo. Saludos
ResponderEliminarEl mejor post que he encontrado sobre el tema, mil gracias!!
ResponderEliminarTenía otro idéntico pero NO era una lista, y cada vez que le agregaba una entrada, se cambiaban las --p-- por --div-- y ya no me funcionaba y tenía que volver a configurar de nuevo. Espero que con este no me ocurra lo mismo, de momento funciona, solo que se desplaza a la derecha los enlaces, por favor dime si puedo corregirlo. ¡¡Gracias!! te dejo el enlace al blog. http://doshermanasayeryhoy.blogspot.com.es/
ResponderEliminarPrueba a añadir al CSS esto:
Eliminar.widget .menujq ul ul {
padding: 0;
}
estimado no vi cambio con ese agregado. q deveria ver? como limito el ancho de todo el menu? gracias
EliminarHola Ariel ¿qué quieres hacer exactamente? ¿Cuál es tu blog?
EliminarHola como estas? queria ahcer una emnud esplegable eso es. ya limite el ancho lo que no se como ahcer es que no despleque cuando no tiene hijos el menu principal. lo que no note es ningun cambio cuando agregue esto:
Eliminar.widget .menujq ul ul {
padding: 0;
}
que deberia ver? no tengo un blog. gracias
Con este código ese tema es automático. No tienes que añadir nada. Simplemente, los enlaces que no tienen hijos serán como ese del ejemplo en el que puse "enlace directo" y el HREF en lugar de javascript:void(); tendrás que poner la dirección de destino:
Eliminar<li><a href="URL del enlace">Opción3 Directa</a></li>
Perfecto lo he añadido al final del CSS, y funciona de maravilla. Eres un "artista" muchas GRACIAS de nuevo.
ResponderEliminarGenial olo que detalle ,como me encanta aprender eres un artista, eh visto cosas que me imaginaba pero voy dándole un repaso . Un saludo
ResponderEliminarMuy bueno, sigo investigando y aprendiendo. Gracias
ResponderEliminarGracias por el aporte. Me gustaría poder hacer una pequeña variación: que al situar el puntero sobre cada item del menú principal, se desplegase el correspondiente submenú, sin clicar. Cómo podría hacerlo? Gracias
ResponderEliminarNo sé seguro si va a funcionar porque ahora mismo voy a toda pastilla contestando comentarios atrasados y no tengo tiempo para probarlo, pero prueba tú a cambiar el .click del último trozo de código por un .mouseover
EliminarGracias Oloman, no he podido probar porque tu código no me funciona, así tal y como está publicado. El Dreamweaver me dice que hay un error de sintaxis en la línea 3 del js, no sé si puede ser eso
ResponderEliminarEra error mío, perdón, sin embargo no me funciona
ResponderEliminarPatrici4, el código que puse es correcto porque además de en CodePen, en esta entrada puedes comprobar que funciona. Seguramente es porque estás en Dreamweaver. Prueba en real.
EliminarGracias Oloman, era correcto el .mouseover. Perfecto!
ResponderEliminarHOla la verdad es que esta super genial este menú pero tengo un problema, cuando quiero desplegar la pestaña no me sale nada, quiero pensar que son por los códigos de script pero no estoy segura, a que se debe??
ResponderEliminarEl código está bien Vicky, así que lo que te sugiero es que copies lo de esta entrada tal cual y una vez que compruebes que todo funciona correctamente en tu propia página, que entonces reestructures el HTML que forma el menú (primer trozo de código de este post) para que salga como tú necesitas.
EliminarOjo con el anidamiento de UL y LI, porque es fácil errar ahí.
Esta super tu menu pero como hago para mentener abierto el los submenus al seleccionar otro
ResponderEliminarCambiando el JavaScript que puse por este otro:
Eliminar$(document).ready(function(){
$('.menujq > ul > li:has(ul)').addClass('desplegable');
$('.menujq > ul > li > a').click(function() {
var comprobar = $(this).next();
$(this).closest('li').addClass('activa');
if((comprobar.is('ul')) && (comprobar.is(':visible'))) {
$(this).closest('li').removeClass('activa');
}
$(this).next().slideToggle();
});
});
Una pregunta de principiante seguramente.... cómo tengo que nombrar el .js para que quede linkeado al html? Gracias de antemano..
ResponderEliminarDaniel, si tienes Blogger no necesitas nombrar la parte JavaScript ni enlazarla de ninguna manera. Directamente la copias y pegas justo antes del </head> de tu plantilla y funcionará sin problemas. En este post no expliqué dónde va cada parte de código que cito, pero es que ya lo digo en todos y de vez en cuando... descanso.
Eliminarhola una consulta estos codigos se puede adaptar para paginas hechas con jimdo?
ResponderEliminarmuchas gracias por su respuesta...saludos.
Hola Willy. Se pueden colocar en cualquier tipo de sitio web. Sólo es cuestión de poner HTML, CSS y JavaScript, cada cual en su sitio. Yo indico dónde se inserta cada cosa en Blogger, pero en esa plataforma no te sé indicar.
Eliminarbonito menú, Es posible agregar otro nivel
ResponderEliminarSí, claro. En el enlace a Codepen del principio de esta entrada puedes ver este mismo código pero con un subnivel más.
EliminarHola! me sirvió mucho el .js que permite dejar abierto el desplegable al seleccionar cualquiera de las OpcionX desplegable. Ahora, te hago una consulta, si quiero mantener también el desplegable abierto cuando selecciono cualquiera de las Opc x.x, que debería hacer? Necesito que el submenú despegable quede abierto en la opc que elija y no que se cierre al seleccionar uno de estos... se entiende?? espero me puedas ayudar xq estoy dando vueltas c esto hace mil años!!!
ResponderEliminarUn poco más arriba, en el comentario 13 y siguiente lo tienes Paine
EliminarHola! cómo sería el script si quisiera tener un submenú abierto desde el principio?
ResponderEliminargracias
No hace falta que cambies el script. Lo que tendrías que hacer sería añadir al LI que quieres tener desplegado un class="active" y al UL que hay dentro de él un style="display:block;"
EliminarBuenas, no sé si los comentarios primero los tienes que aprobar para que aparezcan o no lo llegué a mandar bien el mensaje, por lo que por si acaso te mando de nuevo. Si he hecho mal, te pido disculpas ya que entiendo que a parte de esto también tendrás otras cosas.
ResponderEliminarTal y como puse en el comentario anterior, el código me funciona de lujo, pero me gustaría que el menú fuese responsive ya que si lo veo en el móvil, pues no sé ve bien, y quisiera hacerlo de esots menus que aparecen en el lateral, no sé si me explico.
Pues un saludo y si he hecho mal en poner otro mensaje, este borralo y mis más sinceras disculpas
Aritz, este menú es "responsive", pues si la ventana del navegador es más pequeña, automáticamente se adapta a ese ancho.
EliminarPero por lo que entiendo, lo que tú quieres es que tamaños pequeños de ventana, el menú adopte otro formato. Eso ya es otra cosa y no esta. Se trataría de tener en realidad dos formatos de menú y según el ancho, mostrar uno u otro. Eso lo sé hacer de varias formas, pero ninguna de ellas la he explicado todavía en el blog. En alguna ocasión tocará...
Bueno eso más o menos, pero me interesa que se siga viendo con ese diseño en todo tipo de pantallas, aunque luego lo que sí que querría es que el menú salga por ejemplo por la derecha o izquierda, no sé si me explico. Ahora tengo el menú que en pantalla de pc lo abro, se despliega y todo bien, como lo uso en pantalla principal no hay scroll ni nada por el estilo por lo que hace lo que me interesa. Pero si me voy al móvil, al abrir el menú pues lo hace de igual forma pero al tener una lista larga, el footer que tengo se me va para abajo hasta que termina la lista, por lo que mi intención es que al pulsar para desplegar el menú, este salga por la izquierda o derecha y que el fondo se quede como está. Es decir, que haga más o menos la misma función que cuando creas un combobox con select option,
EliminarEsto que te cuento entiendo que también pertenece a lo que comentas tú que aún no está escrito en el blog por lo estaré atento
¿Quizás quieres algo como esto pero sólo para móvil?
EliminarPues viendo el código fuente puedes averiguar cómo lo hice.
El problema que tengo a la hora de publicar el sistema es que sería complicado y largo de desarrollar en un post que lo explique de forma genérica y que sirva para todas las plantillas y eso es precisamente es lo que me propongo cuando publico algún artículo. Los casos particulares los trato de otra manera.
hola quisiera saber si es posible poner dentro de un acordeon, otro acordeon es decir en el panel del primer acordeon el contenido seria otro acordios hijo. Lohe intentado pero se me muestra solo el heder de los paneles del hijo y no se despliega. trabajo en asp.net c# y estoy usando controles de ajax toolkit, pero cualquier cosa que me de una idea pueda llevarla a lo mio, gracias de ante mano
ResponderEliminarHola Orleni
EliminarEn este Codepen tienes un ejemplo de eso. Pincha en la opción 1 y luego en la 1.3
Hola. Sabes como puedo hacer que la lista de la opción desplegable permanezca abierta cuando selecciono un enlace?
ResponderEliminarHola. Echa un vistazo al comentario 13 porque creo que es lo mismo que preguntas.
EliminarNo. Lo ensayé y no es igual. Con este Javascript puedo tener todos los menús abiertos. Lo que busco es que cuando de click en el enlace del menú este no se cierre, pues termino perdida sin saber en que parte del blog estoy...
EliminarEl enlace no se cierra Tortuga ¿quizás quieres decir que cuando pinchas en un enlace te cambia de página y entonces aparece el menú de nuevo cerrado?
EliminarVa siendo el momento de que me digas en qué página lo tienes puesto para echar un vistazo y entender qué es lo que ocurre.
Si, es lo que pasa. Este es mi blog http://tortuga-taller.blogspot.com/
EliminarOK. Para que al cambiar de página (tras pinchar en un enlace del menú), las opciones se queden desplegadas tal y como estaban antes de saltar de página, sería necesario un sistema de cookies para que recordara la "última diposición" del menú para cada usuario. Sinceramente, no creo que merezca la pena cargar más de código la plantilla para eso, pero es que además me llevaría un post entero explicártelo.
EliminarSi sabes manejar eso la idea al menos sí que te servirá.
Listo. Muchas gracias por responder...
EliminarHola, como hago para cambiar el icono de la flechita (abierta y cerrada) por otro?
ResponderEliminarHola. Eso lo tienes en esta parte del CSS:
Eliminar/* Símbolo elemento normal */
.menujq ul li a:before {
content: "\25CF\00A0 ";
width: 28px;
display: inline-block;
vertical-align: top;
}
/* Símbolo elemento desplegable cerrado */
.menujq ul li.desplegable a:before {
content: "\25BA\00A0";
}
/* Símbolo elemento desplegable abierto */
.menujq ul li.desplegable.activa a:before {
content: "\25BC\00A0 ";
}
Sería cambiando lo que hay dentro de "content" por el código ISO del símbolo (entidad HTML) que quieras poner
Hola, tengo un problema con la librerías, tengo puesto un slider y al poner esta librería se me anula.
ResponderEliminar¿Alguna solución? Soy un poco novato en esto.
Gracias
Hola Start. Prueba a usar jQuery en modo "noconflict". En este enlace tienes la referencia.
EliminarLuego de eso has de sustituir todos los símbolos $ por la palabra jQuery.
Ok, Gracias
ResponderEliminarCómo podríamos hacer que se abran las pestañas pulsando en unos iconos que se encuentren arriba del acordeón? Y que cada uno de estos abra cada una de las secciones correspondientes
ResponderEliminarHola Pedro. Eso sería similar a esto pero el desarrollo del código sería bastante distinto. Es decir, que habría que crear un código diferente.
EliminarHola amigo! Habría alguna posibilidad de hacer esto mismo pero solo con CSS? Sin necesidad de Js o jQuery?
ResponderEliminarPor supuesto :)
EliminarTras la broma, tengo previsto publicar un post precisamente sobre ello. Será en unos días, pero no sé cuántos.
Eliminarhola, disculpa, pero no me funciona lo que es el desplegable y creo que es por la etiqueta script , donde la coloco exactamente? tanto esa etiqueta como el javascript lo he colocado en la cabecera del tema , antes de cerrar el head, pero nada..
ResponderEliminarHola Álvaro ¿quizás olvidaste poner la librería jQuery?
EliminarSi teniéndola sigue sin funcionar, prueba con el JavaScript antes del </body>
Buenas Oloman!
ResponderEliminarAl tratar de poner el JS me tira un error " Error al analizar XML, línea 1115, columna 26: The entity name must immediately follow the '&' in the entity reference." ¿A qué puede deberse?
A que a Blogger hay cosas que no le sientan bien.
EliminarCambia todos los & que veas en el código propuesto por &
Mil gracias por este aporte, tenia muchos problemas para agregar otro tercer nivel
ResponderEliminarHola Oloman. He aplicado tal cual el código y excelente. Gracias. Por otro lado, cuando entro en un enlace y regreso atras, no me queda el menú tal cual inicié la aplicación, sino que me muestra en un listado todas las palabras (y sus palabras contenidas). Nuevamente gracias por todo. Un cordial saludo desde Mataró
ResponderEliminarNo entiendo bien qué es lo que te pasa. Si me ofreces un enlace dónde verlo...
EliminarHola como estás? lo realicé en un blog de prueba y me queda un ">" antes de cada despliegue, mi dirías como eliminarlo??
ResponderEliminarte dejo el blog https://stlacadee.blogspot.com/p/entrenamiento.html