Cómo hacer que el menú desplegable de Twitter Bootstrap se desplace en lugar de hacer clic

Me gustaría tener mi menú Bootstrap automáticamente desplegable al pasar el mouse, en lugar de tener que hacer clic en el título del menú. También me gustaría perder las pequeñas flechas junto a los títulos del menú.

Creé un menú desplegable puro al pasar el ratón basado en el último framework de Bootstrap (v2.0.2) que tiene soporte para múltiples submenús y pensé que lo publicaría para futuros usuarios:

body { padding-top: 60px; padding-bottom: 40px; } .sidebar-nav { padding: 9px 0; } .dropdown-menu .sub-menu { left: 100%; position: absolute; top: 0; visibility: hidden; margin-top: -1px; } .dropdown-menu li:hover .sub-menu { visibility: visible; } .dropdown:hover .dropdown-menu { display: block; } .nav-tabs .dropdown-menu, .nav-pills .dropdown-menu, .navbar .dropdown-menu { margin-top: 0; } .navbar .sub-menu:before { border-bottom: 7px solid transparent; border-left: none; border-right: 7px solid rgba(0, 0, 0, 0.2); border-top: 7px solid transparent; left: -7px; top: 10px; } .navbar .sub-menu:after { border-top: 6px solid transparent; border-left: none; border-right: 6px solid #fff; border-bottom: 6px solid transparent; left: 10px; top: 11px; left: -6px; } 
   

Para hacer que el menú caiga automáticamente al pasar el mouse, esto puede lograrse usando CSS básico. Debe configurar el selector en la opción del menú oculto y luego configurarlo para que se muestre como bloque cuando se coloca la etiqueta li correspondiente. Tomando el ejemplo de la página de arranque de Twitter, el selector sería el siguiente:

 ul.nav li.dropdown:hover > ul.dropdown-menu { display: block; } 

Sin embargo, si está utilizando las funciones de respuesta de Bootstrap, no querrá esta funcionalidad en una barra de navegación comprimida (en pantallas más pequeñas). Para evitar esto, ajuste el código anterior en una consulta de medios:

 @media (min-width: 979px) { ul.nav li.dropdown:hover > ul.dropdown-menu { display: block; } } 

Para ocultar la flecha (símbolo de intercalación), esto se hace de diferentes maneras, dependiendo de si está utilizando Twitter Bootstrap versión 2 o inferior o versión 3:

Bootstrap 3

Para eliminar el símbolo de intercalación en la versión 3, solo tiene que eliminar el HTML del elemento de anclaje .dropdown-toggle :

  Dropdown  < -- remove this line  

Bootstrap 2 y más bajo

Para eliminar el símbolo de intercalación en la versión 2, necesita un poco más de información sobre CSS y sugiero ver cómo funciona :after pseudo element en más detalle. Para que pueda comenzar a comprender, apuntar y eliminar las flechas en el ejemplo de arranque de Twitter, debería usar el siguiente selector y código CSS:

 a.menu:after, .dropdown-toggle:after { content: none; } 

Trabajará a su favor si profundiza en cómo funcionan y no solo utiliza las respuestas que le he dado.

Gracias a @CocaAkat por señalar que nos faltaba el combinador de elementos “>” para evitar que se mostraran submenús en el control deslizante principal

Además de la respuesta de “My Head Hurts” (que fue genial):

 ul.nav li.dropdown:hover ul.dropdown-menu{ display: block; } 

Hay 2 problemas persistentes:

  1. Al hacer clic en el enlace desplegable, se abrirá el menú desplegable. Y permanecerá abierto a menos que el usuario haga clic en otro lugar, o se desplace sobre él, creando una IU incómoda.
  2. Hay un margen de 1px entre el enlace desplegable y el menú desplegable. Esto hace que el menú desplegable se oculte si se mueve lentamente entre el menú desplegable y el menú desplegable.

La solución a (1) es eliminar los elementos “class” y “data-toggle” del enlace de navegación

  Dropdown   

Esto también le da la posibilidad de crear un enlace a su página primaria, lo que no fue posible con la implementación predeterminada. Simplemente puede reemplazar el “#” con la página que desee enviar al usuario.

La solución a (2) es eliminar el margen superior en el selector .downdown-menu

 .navbar .dropdown-menu { margin-top: 0px; } 

He usado un poco de jQuery:

 // Add hover effect to menus jQuery('ul.nav li.dropdown').hover(function() { jQuery(this).find('.dropdown-menu').stop(true, true).delay(200).fadeIn(); }, function() { jQuery(this).find('.dropdown-menu').stop(true, true).delay(200).fadeOut(); }); 

Aquí hay muchas soluciones realmente buenas. Pero pensé que seguiría adelante y pondría la mía aquí como otra alternativa. Es solo un simple fragmento de jQuery que lo hace de la misma forma que lo haría el bootstrap si soportara desplazarse por desplegables en lugar de simplemente hacer clic. Solo he probado esto con la versión 3, así que no sé si funcionaría con la versión 2. Guárdalo como un fragmento en tu editor y escríbelo con solo presionar una tecla.

  

Básicamente, solo dice que cuando coloque el cursor sobre la clase desplegable, agregará la clase abierta a ella. Entonces solo funciona. Cuando dejas de pasar el cursor sobre el li parental con la clase desplegable o el hijo ul / li’s, elimina la clase abierta. Obviamente, esta es solo una de muchas soluciones, y puede agregarla para que funcione únicamente en instancias específicas de .downdown. O agregue una transición a padre o hijo.

Simplemente personalice su estilo CSS en tres líneas de código

 .dropdown:hover .dropdown-menu { display: block; } 

Si tiene un elemento con una clase dropdown como este (por ejemplo):

  

Luego puede hacer que el menú desplegable se despliegue automáticamente al pasar el mouse sobre el mouse, en lugar de tener que hacer clic en su título, usando este fragmento de código jQuery:

  

Aquí hay una demostración

Esta respuesta se basó en la respuesta de @Michael , realicé algunos cambios y agregué algunas adiciones para que el menú desplegable funcione correctamente.

[Actualización] El complemento está en GitHub y estoy trabajando en algunas mejoras (como el uso solo con datos-atributos (no es necesario JS). He dejado el código a continuación, pero no es lo mismo que lo que está en GitHub.

Me gustó la versión puramente CSS, pero es agradable tener un retraso antes de que se cierre, ya que generalmente es una mejor experiencia de usuario (es decir, no se castiga con un deslizamiento de mouse que va 1 px fuera del menú desplegable, etc.) y como se menciona en los comentarios , hay ese 1px de margen con el que tiene que lidiar o, a veces, el navegador se cierra inesperadamente cuando se mueve al menú desplegable del botón original, etc.

Creé un pequeño plugin rápido que he usado en un par de sitios y funcionó muy bien. Cada elemento de navegación se maneja de forma independiente, por lo que tienen sus propios temporizadores de retardo, etc.

JS

 // outside the scope of the jQuery plugin to // keep track of all dropdowns var $allDropdowns = $(); // if instantlyCloseOthers is true, then it will instantly // shut other nav items when a new one is hovered over $.fn.dropdownHover = function(options) { // the element we really care about // is the dropdown-toggle's parent $allDropdowns = $allDropdowns.add(this.parent()); return this.each(function() { var $this = $(this).parent(), defaults = { delay: 500, instantlyCloseOthers: true }, data = { delay: $(this).data('delay'), instantlyCloseOthers: $(this).data('close-others') }, options = $.extend(true, {}, defaults, options, data), timeout; $this.hover(function() { if(options.instantlyCloseOthers === true) $allDropdowns.removeClass('open'); window.clearTimeout(timeout); $(this).addClass('open'); }, function() { timeout = window.setTimeout(function() { $this.removeClass('open'); }, options.delay); }); }); }; 

El parámetro de delay es bastante explicativo, y instantlyCloseOthers cerrará al instante todas las demás listas desplegables que se abren cuando pasas el cursor sobre una nueva.

No es CSS puro, pero con suerte ayudará a alguien más a esta hora tardía (es decir, este es un hilo viejo).

Si lo desea, puede ver los diferentes procesos que realicé (en una discusión sobre el IRC #concrete5 ) para que funcione a través de los diferentes pasos de esta esencia: https://gist.github.com/3876924

El enfoque del patrón de complementos es mucho más limpio para admitir temporizadores individuales, etc.

Vea la publicación del blog para más.

Esto funcionó para mí:

 .dropdown:hover .dropdown-menu { display: block; } 

Mejor aún con jQuery:

 jQuery('ul.nav li.dropdown').hover(function() { jQuery(this).find('.dropdown-menu').stop(true, true).show(); jQuery(this).addClass('open'); }, function() { jQuery(this).find('.dropdown-menu').stop(true, true).hide(); jQuery(this).removeClass('open'); }); 

Puede usar el método desplegable predeterminado $().dropdown('toggle') para alternar el menú desplegable al desplazarse:

 $(".nav .dropdown").hover(function() { $(this).find(".dropdown-toggle").dropdown("toggle"); }); 

Esto está integrado en Bootstrap 3. Solo agregue esto a su CSS:

 .dropdown:hover .dropdown-menu { display: block; } 

Solo quiero agregar, que si tienes varias listas desplegables (como yo) debes escribir:

 ul.nav li.dropdown:hover > ul.dropdown-menu { display: block; } 

Y funcionará correctamente.

La mejor forma de hacerlo es activar el evento de clic de Bootstrap con un vuelo estacionario. De esta forma, aún debe permanecer amigable para dispositivos táctiles.

 $('.dropdown').hover(function(){ $('.dropdown-toggle', this).trigger('click'); }); 

En mi opinión, la mejor manera es la siguiente:

 ;(function($, window, undefined) { // Outside the scope of the jQuery plugin to // keep track of all dropdowns var $allDropdowns = $(); // If instantlyCloseOthers is true, then it will instantly // shut other nav items when a new one is hovered over $.fn.dropdownHover = function(options) { // The element we really care about // is the dropdown-toggle's parent $allDropdowns = $allDropdowns.add(this.parent()); return this.each(function() { var $this = $(this), $parent = $this.parent(), defaults = { delay: 500, instantlyCloseOthers: true }, data = { delay: $(this).data('delay'), instantlyCloseOthers: $(this).data('close-others') }, settings = $.extend(true, {}, defaults, options, data), timeout; $parent.hover(function(event) { // So a neighbor can't open the dropdown if(!$parent.hasClass('open') && !$this.is(event.target)) { return true; } if(settings.instantlyCloseOthers === true) $allDropdowns.removeClass('open'); window.clearTimeout(timeout); $parent.addClass('open'); }, function() { timeout = window.setTimeout(function() { $parent.removeClass('open'); }, settings.delay); }); // This helps with button groups! $this.hover(function() { if(settings.instantlyCloseOthers === true) $allDropdowns.removeClass('open'); window.clearTimeout(timeout); $parent.addClass('open'); }); // Handle submenus $parent.find('.dropdown-submenu').each(function(){ var $this = $(this); var subTimeout; $this.hover(function() { window.clearTimeout(subTimeout); $this.children('.dropdown-menu').show(); // Always close submenu siblings instantly $this.siblings().children('.dropdown-menu').hide(); }, function() { var $submenu = $this.children('.dropdown-menu'); subTimeout = window.setTimeout(function() { $submenu.hide(); }, settings.delay); }); }); }); }; $(document).ready(function() { // apply dropdownHover to all elements with the data-hover="dropdown" attribute $('[data-hover="dropdown"]').dropdownHover(); }); })(jQuery, this); 

Marcado de muestra:

  

Lo he logrado de la siguiente manera:

 $('ul.nav li.dropdown').hover(function(){ $(this).children('ul.dropdown-menu').slideDown(); }, function(){ $(this).children('ul.dropdown-menu').slideUp(); }); 

Espero que esto ayude a alguien…

También se agregó margen superior: 0 para restablecer el margen de arranque css para el menú desplegable, por lo que la lista del menú no desaparecerá cuando el usuario pase lentamente del menú desplegable a la lista del menú.

 ul.nav li.dropdown:hover > ul.dropdown-menu { display: block; } .nav .dropdown-menu { margin-top: 0; } 

Esta es probablemente una idea estúpida, pero para eliminar la flecha que apunta hacia abajo, puede eliminar

  

Esto no hace nada para el que apunta hacia arriba, sin embargo …

Utilice este código para abrir el submenú en mousehover (solo escritorio):

 $('ul.nav li.dropdown').hover(function () { if ($(window).width() > 767) { $(this).find('.dropdown-menu').show(); } }, function () { if ($(window).width() > 767) { $(this).find('.dropdown-menu').hide().css('display',''); } }); 

Y si desea que se pueda hacer clic en el menú del primer nivel, incluso en un dispositivo móvil, agregue esto:

  $('.dropdown-toggle').click(function() { if ($(this).next('.dropdown-menu').is(':visible')) { window.location = $(this).attr('href'); } }); 

El submenú (menú desplegable) se abrirá con mousehover en el escritorio y con clic / toque en el móvil y la tableta. Una vez que el submenú estuvo abierto, un segundo clic le permitirá abrir el enlace. Gracias a if ($(window).width() > 767) , el submenú tendrá el ancho de pantalla completa en el móvil.

 $('.dropdown').hover(function(e){$(this).addClass('open')}) 

He publicado un complemento adecuado para la funcionalidad desplegable Bootstrap 3, en la que incluso puede definir lo que sucede al hacer clic en el elemento dropdown-toggle (se puede desactivar el clic):

https://github.com/istvan-ujjmeszaros/bootstrap-dropdown-hover


¿Por qué lo hice cuando ya hay muchas soluciones?

Tuve problemas con todas las soluciones existentes anteriormente. Los CSS simples no están usando la clase .open en .dropdown , por lo que no habrá comentarios en el elemento de alternancia desplegable cuando el menú desplegable esté visible.

Los js están interfiriendo con hacer clic en .dropdown-toggle , por lo que el menú desplegable se muestra al pasar el cursor, luego lo oculta al hacer clic en un menú desplegable abierto, y al mover el mouse se activará el menú desplegable nuevamente. Algunas de las soluciones js están rompiendo la compatibilidad con iOS, algunos complementos no funcionan en los navegadores de escritorio modernos que admiten los eventos táctiles.

Es por eso que hice el plugin Bootstrap Dropdown Hover que previene todos estos problemas usando solo la API javascript estándar de Bootstrap, sin ningún truco . Incluso los atributos de Aria funcionan bien con este complemento.

Esto ocultará los mejores

 .navbar .dropdown-menu:before { display:none; } .navbar .dropdown-menu:after { display:none; } 

Esto debería ocultar los menús desplegables y sus caretas si son más pequeños que una tableta.

 @media (max-width: 768px) { .navbar ul.dropdown-menu, .navbar li.dropdown b.caret { display: none; } } 

La solución de jQuery es buena, pero tendrá que tratar con eventos de clics (para dispositivos móviles o tabletas) ya que el vuelo estacionario no funcionará correctamente … ¿Podría tal vez realizar alguna detección de tamaño de ventana?

La respuesta de Andrés Ilich parece funcionar bien, pero debería estar envuelta en una consulta de medios:

 @media (min-width: 980px) { .dropdown-menu .sub-menu { left: 100%; position: absolute; top: 0; visibility: hidden; margin-top: -1px; } .dropdown-menu li:hover .sub-menu { visibility: visible; } .dropdown:hover .dropdown-menu { display: block; } .nav-tabs .dropdown-menu, .nav-pills .dropdown-menu, .navbar .dropdown-menu { margin-top: 0; } .navbar .sub-menu:before { border-bottom: 7px solid transparent; border-left: none; border-right: 7px solid rgba(0, 0, 0, 0.2); border-top: 7px solid transparent; left: -7px; top: 10px; } .navbar .sub-menu:after { border-top: 6px solid transparent; border-left: none; border-right: 6px solid #fff; border-bottom: 6px solid transparent; left: 10px; top: 11px; left: -6px; } } 

Sobrescribe bootstrap.js con este script.

 jQuery(document).ready(function ($) { $('.navbar .dropdown').hover(function() { $(this).addClass('extra-nav-class').find('.dropdown-menu').first().stop(true, true).delay(250).slideDown(); }, function() { var na = $(this) na.find('.dropdown-menu').first().stop(true, true).delay(100).slideUp('fast', function(){ na.removeClass('extra-nav-class') }) }); $('.dropdown-submenu').hover(function() { $(this).addClass('extra-nav-class').find('.dropdown-menu').first().stop(true, true).delay(250).slideDown(); }, function() { var na = $(this) na.find('.dropdown-menu').first().stop(true, true).delay(100).slideUp('fast', function(){ na.removeClass('extra-nav-class') }) }); }); 

Esta es mi técnica que agrega un ligero retraso antes de que el menú se cierre después de dejar de pasar el ratón sobre el menú o el botón de alternar. El que normalmente haría clic para mostrar el menú de navegación es #nav_dropdown .

 $(function() { var delay_close_it, nav_menu_timeout, open_it; nav_menu_timeout = void 0; open_it = function() { if (nav_menu_timeout) { clearTimeout(nav_menu_timeout); nav_menu_timeout = null; } return $('.navbar .dropdown').addClass('open'); }; delay_close_it = function() { var close_it; close_it = function() { return $('.navbar .dropdown').removeClass('open'); }; return nav_menu_timeout = setTimeout(close_it, 500); }; $('body').on('mouseover', '#nav_dropdown, #nav_dropdown *', open_it).on('mouseout', '#nav_dropdown', delay_close_it); return $('body').on('mouseover', '.navbar .dropdown .dropdown-menu', open_it).on('mouseout', '.navbar .dropdown .dropdown-menu', delay_close_it); }); 

Para mejorar la respuesta de Sudharshan, envuelvo esto en una consulta de medios para evitar el vuelo estacionario cuando el ancho de la pantalla XS …

 @media (min-width:768px) { ul.nav li.dropdown:hover > ul.dropdown-menu { display: block; } .nav .dropdown-menu { margin-top: 0; } } 

Además, no se requiere la referencia en el marcado, solo la clase desplegable para el li .

Esto funciona para WordPress Bootstrap:

 .navbar .nav > li > .dropdown-menu:after, .navbar .nav > li > .dropdown-menu:before { content: none; } 

Entonces tienes este código:

 Show menu  

Normalmente funciona en un evento de clic y desea que funcione en un evento de desplazamiento. Esto es muy simple, solo usa este código JavaScript / jQuery:

 $(document).ready(function () { $('.dropdown-toggle').mouseover(function() { $('.dropdown-menu').show(); }) $('.dropdown-toggle').mouseout(function() { t = setTimeout(function() { $('.dropdown-menu').hide(); }, 100); $('.dropdown-menu').on('mouseenter', function() { $('.dropdown-menu').show(); clearTimeout(t); }).on('mouseleave', function() { $('.dropdown-menu').hide(); }) }) }) 

Esto funciona muy bien y aquí está la explicación: tenemos un botón y un menú. Cuando movemos el botón, mostramos el menú, y cuando movemos el mouse sobre el botón, ocultamos el menú después de 100 ms. Si se pregunta por qué lo uso, es porque necesita tiempo para arrastrar el cursor desde el botón sobre el menú. Cuando está en el menú, la hora se restablece y puede permanecer allí el tiempo que desee. Cuando salga del menú, ocultaremos el menú al instante sin tiempo de espera.

He utilizado este código en muchos proyectos, si tiene algún problema al usarlo, siéntase libre de hacerme preguntas.

Para el cursor … No he visto a nadie especificando un CSS simple que bloquee totalmente el cursor.

Aqui tienes:

 .caret { display: none !important; }