Comment faire dérouler le menu Twitter Bootstrap en survol plutôt qu'en cliquant


1184

J'aimerais que mon menu Bootstrap se déroule automatiquement au survol, plutôt que d'avoir à cliquer sur le titre du menu. J'aimerais aussi perdre les petites flèches à côté des titres de menu.


9
Il y a une solution pour cela, donc la réponse de mikko est correcte mais couverte maintenant avec un plugin pour spécifiquement cette situation. bootstrap-hover-dropdown
HenryW

2
Voir mon plugin approprié récemment publié qui empêche les problèmes des solutions CSS et js ci-dessous, et fonctionne correctement sur iOS et sur les navigateurs de bureau modernes avec des événements tactiles. Même les attributs aria fonctionnent bien avec cela: github.com/istvan-ujjmeszaros/bootstrap-dropdown-hover
István Ujj-Mészáros

J'ai fait une liste déroulante pure CSS3 avec une barre de navigation bootstrap, vérifiez-la sur CodePen Pure CSS3 Dropdown
Gothburz

18
Réfléchissez-y à deux fois si vous en avez vraiment besoin? Bootstrap utilise pour les sites adaptatifs. Cela signifie qu'ils seront également utilisés sur les appareils dotés de commandes tactiles. C'est pourquoi il est conçu de cette façon. Il n'y a pas de "survol" sur les écrans tactiles.
Serj.by

Réponses:


592

J'ai créé un menu déroulant pur en survol basé sur le dernier framework Bootstrap (v2.0.2) qui prend en charge plusieurs sous-menus et j'ai pensé le publier pour les futurs utilisateurs:

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;
}
<link href="https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/2.3.2/css/bootstrap.min.css" rel="stylesheet" />

<div class="navbar navbar-fixed-top">
  <div class="navbar-inner">
    <div class="container-fluid">
      <a data-target=".nav-collapse" data-toggle="collapse" class="btn btn-navbar">
        <span class="icon-bar"></span>
        <span class="icon-bar"></span>
        <span class="icon-bar"></span>
      </a>
      <a href="#" class="brand">Project name</a>
      <div class="nav-collapse">
        <ul class="nav">
          <li class="active"><a href="#">Home</a></li>
          <li><a href="#">Link</a></li>
          <li><a href="#">Link</a></li>
          <li><a href="#">Link</a></li>
          <li class="dropdown">
            <a data-toggle="dropdown" class="dropdown-toggle" href="#">Dropdown <b class="caret"></b></a>
            <ul class="dropdown-menu">
              <li>
                <a href="#">2-level Dropdown <i class="icon-arrow-right"></i></a>
                <ul class="dropdown-menu sub-menu">
                  <li><a href="#">Action</a></li>
                  <li><a href="#">Another action</a></li>
                  <li><a href="#">Something else here</a></li>
                  <li class="divider"></li>
                  <li class="nav-header">Nav header</li>
                  <li><a href="#">Separated link</a></li>
                  <li><a href="#">One more separated link</a></li>
                </ul>
              </li>
              <li><a href="#">Another action</a></li>
              <li><a href="#">Something else here</a></li>
              <li class="divider"></li>
              <li class="nav-header">Nav header</li>
              <li><a href="#">Separated link</a></li>
              <li><a href="#">One more separated link</a></li>
            </ul>
          </li>
        </ul>
        <form action="" class="navbar-search pull-left">
          <input type="text" placeholder="Search" class="search-query span2">
        </form>
        <ul class="nav pull-right">
          <li><a href="#">Link</a></li>
          <li class="divider-vertical"></li>
          <li class="dropdown">
            <a class="#" href="#">Menu</a>
          </li>
        </ul>
      </div>
      <!-- /.nav-collapse -->
    </div>
  </div>
</div>

<hr>

<ul class="nav nav-pills">
  <li class="active"><a href="#">Regular link</a></li>
  <li class="dropdown">
    <a href="#" data-toggle="dropdown" class="dropdown-toggle">Dropdown <b class="caret"></b></a>
    <ul class="dropdown-menu" id="menu1">
      <li>
        <a href="#">2-level Menu <i class="icon-arrow-right"></i></a>
        <ul class="dropdown-menu sub-menu">
          <li><a href="#">Action</a></li>
          <li><a href="#">Another action</a></li>
          <li><a href="#">Something else here</a></li>
          <li class="divider"></li>
          <li class="nav-header">Nav header</li>
          <li><a href="#">Separated link</a></li>
          <li><a href="#">One more separated link</a></li>
        </ul>
      </li>
      <li><a href="#">Another action</a></li>
      <li><a href="#">Something else here</a></li>
      <li class="divider"></li>
      <li><a href="#">Separated link</a></li>
    </ul>
  </li>
  <li class="dropdown">
    <a href="#">Menu</a>
  </li>
  <li class="dropdown">
    <a href="#">Menu</a>
  </li>
</ul>

Démo


54
c'est une décision de conception dans le bootstrap de ne pas ouvrir les
listes

18
tellement bon! J'ai également supprimé de class="dropdown-toggle" data-toggle="dropdown"sorte que seul le survol, et non le clic, déclenche le menu. Notez que lorsque vous utilisez des styles réactifs, les menus sont toujours balayés dans le petit bouton en haut à droite, qui est toujours déclenché par un clic. Grand merci!
ptim

11
Pour éviter la liste déroulante automatique sur les petits appareils (tels que les téléphones) et l'autoriser uniquement à partir d'une largeur minimale de 768px par exemple @media (min-width: 768px) {.dropdown-menu li:hover .sub-menu {visibility: visible;}}et@media (min-width: 768px) {.dropdown:hover .dropdown-menu {display: block;}}
Chris Aelbrecht

1
De plus, pour rendre le lien avec les enfants cliquable, vous devez supprimer le "data-toggle = 'dropdown'" sur la balise <a>.
joan16v

2
Voici un code qui fonctionne avec la dernière version de Bootstrap 3: jsfiddle.net/sgruenwald/2tt8f8xg
Stefan Gruenwald

910

Pour que le menu passe automatiquement en survol, cela peut être réalisé en utilisant CSS de base. Vous devez définir le sélecteur sur l'option de menu masqué, puis le définir pour qu'il s'affiche sous forme de bloc lorsque la libalise appropriée est survolée. En prenant l'exemple de la page d'amorçage twitter, le sélecteur serait le suivant:

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

Cependant, si vous utilisez les fonctionnalités réactives de Bootstrap, vous ne voudrez pas cette fonctionnalité sur une barre de navigation réduite (sur des écrans plus petits). Pour éviter cela, enveloppez le code ci-dessus dans une requête multimédia:

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

Pour masquer la flèche (curseur), cela se fait de différentes manières selon que vous utilisez Twitter Bootstrap version 2 et inférieure ou version 3:

Bootstrap 3

Pour supprimer le curseur dans la version 3, il vous suffit de supprimer le code HTML <b class="caret"></b>de l' .dropdown-toggleélément d'ancrage:

<a class="dropdown-toggle" data-toggle="dropdown" href="#">
    Dropdown
    <b class="caret"></b>    <-- remove this line
</a>

Bootstrap 2 et inférieur

Pour supprimer le signe insertion dans la version 2, vous avez besoin d'un peu plus d'informations sur CSS et je suggère de regarder :afterplus en détail le fonctionnement du pseudo-élément. Pour vous aider à comprendre, à cibler et à supprimer les flèches dans l'exemple d'amorçage twitter, vous devez utiliser le sélecteur CSS et le code suivants:

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

Cela fonctionnera en votre faveur si vous examinez plus en détail leur fonctionnement et pas seulement en utilisant les réponses que je vous ai données.

Merci à @CocaAkat d'avoir signalé qu'il manquait le combinateur enfant ">" pour empêcher l'affichage des sous-menus sur le survol des parents.


79
A également dû ajouter margin: 0;, sinon la marge de 1px ci-dessus .dropdown-menuprovoque un comportement buggy.
Salman von Abbas

12
Solution simple, mais le lien parent n'est toujours pas cliquable. J'utilise le dernier bootstrap avec le thème des racines.
Krunal

5
Remarque: oui, cela fonctionnera dans tous les navigateurs pris en charge par Twitter Bootstrap. @GeorgeEdison Il s'agit de CSS de base - quelle partie ne serait pas prise en charge par IE8? Si vous rencontrez des problèmes, posez une question, pas des commentaires trompeurs.
Ma tête fait mal le

3
@MyHeadHurts: Après quelques recherches supplémentaires - il s'est avéré qu'il s'agissait bien d'un bug Bootstrap et il a été corrigé il y a seulement cinq jours.
Nathan Osman

5
@Krunal pour pouvoir cliquer sur le lien, vous devez supprimer l' data-toggle="dropdown"attribut.
Pherrymason

231

En plus de la réponse de "My Head Hurts" (qui était super):

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

Il y a 2 problèmes persistants:

  1. Cliquer sur le lien déroulant ouvrira le menu déroulant. Et il restera ouvert à moins que l'utilisateur ne clique ailleurs ou qu'il ne survole, créant une interface utilisateur maladroite.
  2. Il y a une marge de 1px entre le lien déroulant et le menu déroulant. Cela provoque le masquage du menu déroulant si vous vous déplacez lentement entre le menu déroulant et le menu déroulant.

La solution à (1) consiste à supprimer les éléments "class" et "data-toggle" du lien nav

<a href="#">
     Dropdown
     <b class="caret"></b>
</a>

Cela vous donne également la possibilité de créer un lien vers votre page parent - ce qui n'était pas possible avec l'implémentation par défaut. Vous pouvez simplement remplacer le "#" par la page que vous souhaitez envoyer à l'utilisateur.

La solution à (2) consiste à supprimer la marge supérieure du sélecteur de menu .dropdown

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

15
Pour corriger le clic délibéré, je viens de supprimer l' data-toggle="dropdown"attribut, qui semblait fonctionner.
Anthony Briggs

5
Solution (2) pour les boutons nav-pill:.nav-pills .dropdown-menu { margin-top: 0px; }
Loren

1
Pour résoudre le problème que j'ai noté ci-dessus li.dropdown: hover> ul.dropdown-menu
Archimedes Trajano

12
la suppression des attributs "class" et "data-toggle" des liens de navigation l'empêche de fonctionner
correctement

1
Si vous avez supprimé l'attribut data-toggle = "dropdown", vous ne pourrez pas étendre le menu déroulant à l'aide du clavier. Ce ne sera donc pas conforme au 508. Comment pouvez-vous désactiver le clic mais conserver la fonctionnalité du clavier?
duyn9uyen

130

J'ai utilisé un peu 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();
});

13
Comme ça. J'utilise JQuery de toute façon avec le truc Bootstrap et permet toujours la fonctionnalité de «clic» par défaut dans les appareils à écran tactile.
Canard à la crème anglaise

Utilisé ceci. J'aime que cela permette toujours la fonctionnalité de clic, pour les mobiles, mais pour les ordinateurs de bureau, le survol est parfait.
Stuart

1
Je l'ai utilisé mais je l'ai également étendu pour être utilisable pour les listes déroulantes qui ne sont pas dans un nav. J'ajoute la classe dropdown-hover à la division btn-group et j'ai utilisé ce chercheur jQuery $ ('ul.nav li.dropdown, .dropdown-hover'). Hover (function () {. Merci!
Brandon

Utilisé celui-ci, joli et petit. La version css ne permettait pas au sous-menu de rester affiché, et 200 ms était trop rapide, je l'ai donc changé en $('ul.nav li.dropdown').hover(function() { $(this).find('.dropdown-menu').stop(true, true).delay(200).fadeIn(); }, function() { $(this).find('.dropdown-menu').stop(true, true).delay(200).fadeOut().hover(function() { $(this).stop(true, true); }); });: Lorsque le sous-menu est en vol stationnaire, arrêtez fadeOut
Damien

cela ne semble pas fonctionner avec jqLite qui est inclus avec anguraljs
nuander

70

Il y a beaucoup de très bonnes solutions ici. Mais j'ai pensé que j'irais de l'avant et mettrais le mien ici comme une autre alternative. C'est juste un simple extrait de jQuery qui le fait comme bootstrap s'il prend en charge le survol pour les listes déroulantes au lieu de simplement cliquer. Je ne l'ai testé qu'avec la version 3, donc je ne sais pas si cela fonctionnerait avec la version 2. Enregistrez-le sous forme d'extrait dans votre éditeur et ayez-le en un seul clic.

<script>
    $(function() {
        $(".dropdown").hover(
            function(){ $(this).addClass('open') },
            function(){ $(this).removeClass('open') }
        );
    });
</script>

Fondamentalement, cela signifie simplement que lorsque vous survolez la classe déroulante, elle y ajoutera la classe ouverte. Ensuite, cela fonctionne. Lorsque vous arrêtez de survoler le parent li avec la classe déroulante ou les ul / li enfants, il supprime la classe ouverte. Évidemment, ce n'est qu'une des nombreuses solutions, et vous pouvez y ajouter pour le faire fonctionner uniquement sur des instances spécifiques de .dropdown. Ou ajoutez une transition au parent ou à l'enfant.


2
Excellente solution! J'ai également supprimé l'attribut data-toggle = "dropdown" du lien afin de rendre le lien supérieur cliquable.
Sergey

C'est une bonne astuce Sergey. Je m'assure toujours que le lien supérieur ne va nulle part afin qu'il fonctionne également sur les tablettes et les téléphones.
stéréoscience

1
@Sergey, je ne recommanderais pas de faire ça. Vous briseriez la fonctionnalité pour les utilisateurs mobiles. Ils ne peuvent pas utiliser la fonction de survol pour ouvrir un menu et doivent pouvoir cliquer dessus.
Paul

2
C'est incroyablement court et facile tout en restant rétrocompatible avec les écrans tactiles. Devrait être voté beaucoup plus.
Max

Ça a l'air vraiment bien. Une idée comment ajouter un peu d'animation en utilisant des transitions CSS?
Fred Rocha

70

Personnalisez simplement votre style CSS en trois lignes de code

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

22

Si vous avez un élément avec une dropdownclasse comme celle-ci (par exemple):

<ul class="list-unstyled list-inline">
    <li class="dropdown">
        <a data-toggle="dropdown" href="#"><i class="fa fa-bars"></i> Dropdown 1</a>
        <ul class="dropdown-menu">
            <li><a href="">Item 1</a></li>
            <li><a href="">Item 2</a></li>
            <li><a href="">Item 3</a></li>
            <li><a href="">Item 4</a></li>
            <li><a href="">Item 5</a></li>
        </ul>
    </li>
    <li class="dropdown">
        <a data-toggle="dropdown" href="#"><i class="fa fa-user"></i> Dropdown 2</a>
        <ul class="dropdown-menu">
            <li><a href="">Item A</a></li>
            <li><a href="">Item B</a></li>
            <li><a href="">Item C</a></li>
            <li><a href="">Item D</a></li>
            <li><a href="">Item E</a></li>
        </ul>
    </li>
</ul>

Ensuite, vous pouvez faire en sorte que le menu déroulant soit automatiquement déroulé au-dessus de la souris, plutôt que d'avoir à cliquer sur son titre, en utilisant cet extrait de code jQuery:

<script>
    $('.dropdown').hover(
        function() {
            $(this).find('.dropdown-menu').stop(true, true).delay(200).fadeIn();
        },
        function() {
            $(this).find('.dropdown-menu').stop(true, true).delay(200).fadeOut();
        }
    );

    $('.dropdown-menu').hover(
        function() {
            $(this).stop(true, true);
        },
        function() {
            $(this).stop(true, true).delay(200).fadeOut();
        }
    );
</script>

Voici une démo

Cette réponse s'est appuyée sur la réponse de @Michael , j'ai apporté quelques modifications et ajouté quelques ajouts pour que le menu déroulant fonctionne correctement


Parfait. Merci beaucoup.
antikbd

20

[Mise à jour] Le plugin est sur GitHub et je travaille sur quelques améliorations (comme utiliser uniquement avec des attributs de données (aucun JS nécessaire). J'ai laissé le code ci-dessous, mais ce n'est pas la même chose que sur GitHub.

J'ai aimé la version purement CSS, mais c'est agréable d'avoir un délai avant sa fermeture, car c'est généralement une meilleure expérience utilisateur (c'est-à-dire non punie pour un glissement de souris qui dépasse 1 px en dehors de la liste déroulante, etc.), et comme mentionné dans les commentaires , il y a 1px de marge que vous devez gérer ou parfois la navigation se ferme de manière inattendue lorsque vous passez au menu déroulant à partir du bouton d'origine, etc.

J'ai créé un petit plugin rapide que j'ai utilisé sur quelques sites et cela a bien fonctionné. Chaque élément de navigation est géré indépendamment, de sorte qu'ils ont leurs propres temporisateurs de retard, 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);
        });
    });
};  

Le delayparamètre est assez explicite, et leinstantlyCloseOthers fermera instantanément toutes les autres listes déroulantes ouvertes lorsque vous survolerez une nouvelle.

Pas du CSS pur, mais j'espère que cela aidera quelqu'un d'autre à cette heure tardive (c'est-à-dire que c'est un vieux fil).

Si vous le souhaitez, vous pouvez voir les différents processus que j'ai passés (dans une discussion sur l' #concrete5IRC) pour le faire fonctionner via les différentes étapes de cet essentiel: https://gist.github.com/3876924

L'approche du modèle de plugin est beaucoup plus propre pour prendre en charge les minuteries individuelles, etc.

Voir l' article de blog pour en savoir plus.


17

Cela a fonctionné pour moi:

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

1
Avec le mobile cependant - c'est étrange.
Radmation

La marge entre le menu et le menu déroulant rend cela inutile.
antikbd

15

Ceci est intégré à Bootstrap 3. Ajoutez simplement ceci à votre CSS:

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

10

Encore mieux avec 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');
});

3
J'ai changé votre code pour jQuery('ul.nav li.dropdown').hover(function() { jQuery(this).closest('.dropdown-menu').stop(true, true).show(); jQuery(this).addClass('open'); }, function() { jQuery(this).closest('.dropdown-menu').stop(true, true).hide(); jQuery(this).removeClass('open'); });que le sous-menu ne s'affiche pas en survol.
farjam

Ce code ne fonctionnera plus avec les dernières versions.
Paul

9

Vous pouvez utiliser la $().dropdown('toggle')méthode par défaut pour basculer le menu déroulant au survol:

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

9

Je veux juste ajouter que si vous avez plusieurs listes déroulantes (comme moi), vous devriez écrire:

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

Et cela fonctionnera correctement.


Mon menu .dropdown avait margin: 2px 0 0;ce qui signifiait une entrée lente de la souris par le dessus a caché le menu prématurément. ul.dropdown-menu{ margin-top: 0; }
Alastair

8

À mon avis, la meilleure façon est la suivante:

;(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);

Exemple de balisage:

<li class="dropdown">
    <a href="#" class="dropdown-toggle" data-toggle="dropdown" data-hover="dropdown" data-delay="1000" data-close-others="false">
        Account <b class="caret"></b>
    </a>
    <ul class="dropdown-menu">
        <li><a tabindex="-1" href="#">My Account</a></li>
        <li class="divider"></li>
        <li><a tabindex="-1" href="#">Change Email</a></li>
        <li><a tabindex="-1" href="#">Change Password</a></li>
        <li class="divider"></li>
        <li><a tabindex="-1" href="#">Logout</a></li>
    </ul>
</li>

5
C'est le travail de Cameron Spear, pensais que je lui donnerais le cri: cameronspear.com/blog/bootstrap-dropdown-on-hover-plugin
kelpie

8

La meilleure façon de le faire est de simplement déclencher l'événement Click de Bootstrap avec un survol. De cette façon, il doit rester convivial pour les appareils tactiles.

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

Résultat indésirable: mousein, click and mouseout laissera le menu ouvert. Ce n'est pas ce que je veux ...
Wietse

En utilisant cela, il exécute la fonction d'amorçage pour ouvrir la liste déroulante, cette fonction fait beaucoup d'autres choses, comme aria-
extended

7

Je l'ai géré comme suit:

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

J'espère que ça aidera quelqu'un...


5

Également ajouté margin-top: 0 pour réinitialiser la marge CSS bootstrap pour .dropdown-menu afin que la liste des menus ne disparaisse pas lorsque l'utilisateur passe lentement du menu déroulant à la liste des menus.

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

.nav .dropdown-menu {
    margin-top: 0;
}

2
c'est la bonne réponse, bootstrap est prêt à survoler lors de la liste déroulante, si la souris ne sort pas du menu déroulant. La suppression de margin-top permet de passer du lien au menu sans interruption et donc sans fermeture automatique du menu. Et cette solution permet de garder le bon comportement pour les appareils tactiles
Nicolas Janel

5

C'est probablement une idée stupide, mais pour supprimer simplement la flèche pointant vers le bas, vous pouvez supprimer le

<b class="caret"></b>

Cela ne fait rien pour celui qui pointe vers le haut, cependant ...


5

J'ai publié un plugin approprié pour la fonctionnalité de survol de la liste déroulante Bootstrap 3, dans lequel vous pouvez même définir ce qui se passe lorsque vous cliquez sur ledropdown-toggle élément (le clic peut être désactivé):

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


Pourquoi je l'ai fait alors qu'il existe déjà de nombreuses solutions?

J'ai eu des problèmes avec toutes les solutions existantes. Les CSS simples n'utilisent pas la .openclasse sur le.dropdown , donc il n'y aura aucun retour sur l'élément à bascule déroulant lorsque le menu déroulant est visible.

Les js interfèrent en cliquant sur .dropdown-toggle , donc la liste déroulante apparaît au survol, puis la masque lorsque vous cliquez sur une liste déroulante ouverte, et en déplaçant la souris, la liste déroulante réapparaîtra. Certaines des solutions js ne respectent pas la compatibilité iOS, certains plugins ne fonctionnent pas sur les navigateurs de bureau modernes qui prennent en charge les événements tactiles.

C'est pourquoi j'ai créé le plugin Bootstrap Dropdown Hover qui empêche tous ces problèmes en utilisant uniquement l'API javascript Bootstrap standard, sans aucun piratage . Même les attributs Aria fonctionnent bien avec ce plugin.


Quelle est votre opinion sur github.com/vadikom/smartmenus ? Je ne peux pas décider, les deux bibliothèques semblent vraiment bien.
Csaba Toth

2
Les menus intelligents ont l'air vraiment bien, il peut être préférable pour les menus. Mon plugin n'est qu'un petit ajout aux listes déroulantes de bootstrap, il ne fait rien de plus que d'ouvrir une liste déroulante en survol, tandis que smartmenu prend également en charge les sous-menus et fait d'autres choses fantaisistes.
István Ujj-Mészáros

1
Merci. Je vois que le code de smartmenu est très complet et qu'il y a aussi beaucoup de CSS. Jusqu'à présent, je suis allé avec bootstrap-dropdown-hover, car il semble faire le travail et plus compact. Je construis un site d'atterrissage avec la barre de navigation du côté gauche.
Csaba Toth

4

Utilisez ce code pour ouvrir le sous-menu au survol de la souris (bureau uniquement):

$('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','');
    }
});

Et si vous voulez que le menu de premier niveau soit cliquable, même sur mobile, ajoutez ceci:

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

Le sous-menu (menu déroulant) sera ouvert avec le survol de la souris sur le bureau et avec un clic / toucher sur le mobile et la tablette. Une fois le sous-menu ouvert, un deuxième clic vous permettra d'ouvrir le lien. Grâce au if ($(window).width() > 767), le sous-menu occupera toute la largeur de l'écran sur mobile.


Je voudrais utiliser votre code, mais j'ai du mal à le faire fonctionner correctement. Tout d'abord, comment supprimer le hover () pour mobile et l'utiliser uniquement pour le bureau? Lorsque j'utilise votre code et que je redimensionne la fenêtre sur mobile, j'obtiens à la fois la fonctionnalité de survol () et de clic (). Mais encore plus étrange ... c'est que ce comportement va s'arrêter Quand je rafraîchis le navigateur, ha! Pourriez-vous me montrer comment résoudre ce problème? J'ai besoin de sous-menus de bureau pour afficher en survol () et cliquez sur () pour afficher les sous-menus sur mobile sans avoir à rafraîchir le navigateur même lors du redimensionnement de la fenêtre pour fonctionner correctement. J'espère que cela est clair
Chris22

ok, cela a du sens et je vais essayer d'exécuter votre solution comme vous le recommandez. Merci!
Chris22

Utilisez cette meilleure méthode: @falter
Farhad Sakhaei


3

Cela masquera ceux

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

3

Cela devrait masquer les listes déroulantes et leurs carets s'ils sont plus petits qu'une tablette.

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

Pourquoi voudriez-vous le cacher? Désormais, les utilisateurs mobiles n'ont aucun moyen d'accéder aux liens qui se trouvent dans le sous-menu. Il est préférable de désactiver l'effet de survol sur un appareil mobile et de conserver le menu déroulant intact. De cette façon, ils peuvent l'ouvrir en cliquant dessus.
Paul

3

La solution jQuery est bonne, mais elle devra gérer les événements de clic (pour mobile ou tablette) car le survol ne fonctionnera pas correctement ... Pourrait peut-être faire une détection de redimensionnement de la fenêtre?

La réponse d'Andres Ilich semble bien fonctionner, mais elle devrait être enveloppée dans une requête médiatique:

@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;
    }
}

3

La solution très simple pour la version 2, uniquement CSS. Conserve la même fonctionnalité conviviale pour mobile et tablette.

@media (min-width: 980px) {
    .dropdown:hover .dropdown-menu {
       display: block;
    }
}

Cela ne fonctionne pas très bien pour certains thèmes où il y a un écart entre l'élément de menu et la liste déroulante. Le menu disparaîtra lorsque la souris se déplacera dans cet espace.
ndbroadbent

2

Remplacez bootstrap.js par ce 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') })
});

}); 

2

Voici ma technique qui ajoute un léger délai avant que le menu ne soit fermé après avoir arrêté de survoler le menu ou le bouton bascule. Le <button>fichier sur lequel vous cliqueriez normalement pour afficher le menu de navigation est #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);
});

2

Pour améliorer la réponse de Sudharshan, j'encapsule cela dans une requête multimédia pour empêcher le survol lorsque sur des largeurs d'affichage XS ...

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

    .nav .dropdown-menu {
        margin-top: 0;
    }
}

De plus, le signe d'insertion dans le balisage n'est pas requis, juste la classe déroulante pour le li .


2

Cela fonctionne pour WordPress Bootstrap:

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

2

Vous avez donc ce code:

<a class="dropdown-toggle" data-toggle="dropdown">Show menu</a>

<ul class="dropdown-menu" role="menu">
    <li>Link 1</li>
    <li>Link 2</li> 
    <li>Link 3</li>                                             
</ul>

Normalement, cela fonctionne sur un événement de clic, et vous voulez qu'il fonctionne sur un événement de survol. C'est très simple, utilisez simplement ce code 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();
        })
    })
})

Cela fonctionne très bien et voici l'explication: nous avons un bouton et un menu. Lorsque nous survolons le bouton, nous affichons le menu, et lorsque nous passons la souris sur le bouton, nous masquons le menu après 100 ms. Si vous vous demandez pourquoi j'utilise cela, c'est parce que vous avez besoin de temps pour faire glisser le curseur du bouton sur le menu. Lorsque vous êtes dans le menu, l'heure est réinitialisée et vous pouvez y rester autant de fois que vous le souhaitez. Lorsque vous quittez le menu, nous masquons le menu instantanément sans aucun délai.

J'ai utilisé ce code dans de nombreux projets, si vous rencontrez des problèmes pour l'utiliser, n'hésitez pas à me poser des questions.

En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.