Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Bootstrap clickable menu on hover

I have customized using jquery the bootstrap navigation whereby instead of clicking to enable the dropdown menu you can simply hover. However, I am trying to get it so the first menu is clickable as currently it is not. For example currently BLOG isn't clickable but I would like it to be. The other categories are clickable.

enter image description here

Does anyone have any experience in this on bootstrap? It is being built on wordpress. The jquery I used to allow the menu to show on hover is:

jQuery(document).ready(function() {

    var mq = window.matchMedia('(min-width: 768px)');
  if (mq.matches) {
    jQuery('ul.navbar-nav li').addClass('hovernav');
  } else {
    jQuery('ul.navbar-nav li').removeClass('hovernav');
  };
    /*
    The addClass/removeClass also needs to be triggered
  on page resize <=> 768px
    */
  if (matchMedia) {
    var mq = window.matchMedia('(min-width: 768px)');
    mq.addListener(WidthChange);
    WidthChange(mq);
  }
    function WidthChange(mq) {
    if (mq.matches) {
      jQuery('ul.navbar-nav li').addClass('hovernav');
    } else {
      jQuery('ul.navbar-nav li').removeClass('hovernav');
    }
  };


});

The css is:

@media (min-width: 768px) {
    .navbar-nav .caret {
        display:none;
    }

    .navbar-nav .open ul {
        display:none;
    }

    .navbar-default .navbar-nav > .open > a,.navbar-default .navbar-nav > .open > a:hover,.navbar-default .navbar-nav > .open > a:focus,.navbar-default .navbar-nav > .active > a,.navbar-default .navbar-nav > .active > a:hover,.navbar-default .navbar-nav > .active > a:focus {
        color:#555;
        background:none;
    }

    .navbar-inverse .navbar-nav > .open > a,.navbar-inverse .navbar-nav > .open > a:hover,.navbar-inverse .navbar-nav > .open > a:focus,.navbar-inverse .navbar-nav > .active > a,.navbar-inverse .navbar-nav > .active > a:hover,.navbar-inverse .navbar-nav > .active > a:focus {
        color:#969696;
        background:none;
    }

    .navbar-default .navbar-nav > .hovernav > a {
        color:#555;
    }

    .navbar-inverse .navbar-nav > .hovernav > a {
        color:#969696;
    }

    .navbar-default .navbar-nav > .hovernav:hover > a,.navbar-default .navbar-nav > .hovernav:hover > a:hover,.navbar-default .navbar-nav > .hovernav:hover > a:focus {
        color:#333;
        background:transparent;
    }

    .navbar-inverse .navbar-nav > .hovernav:hover > a,.navbar-inverse .navbar-nav > .hovernav:hover > a:hover,.navbar-inverse .navbar-nav > .hovernav:hover > a:focus {
        color:#F7F7F7;
        background:transparent;
    }

    .navbar-default .navbar-nav > li:hover {
        background:#e7e7e7;
    }

    .navbar-inverse .navbar-nav > li:hover {
        background:#080808;
    }

    .navbar-nav .hovernav:hover > .dropdown-menu {
        display:block;
    }
}
like image 377
memyselfandmyiphone Avatar asked Dec 22 '13 21:12

memyselfandmyiphone


2 Answers

Problems using matchMedia/media queries to accomplish what you're doing:

Media queries for many touch devices are the same as desktop.

Hover does not exist on touch. IOS takes a hover and one click triggers the dropdown 2 clicks get to the link, BUUUT android doesn't work this way. So on touch devices those drop menus won't be accessible. How to do this correctly:

  1. Detect touch and no-touch on Android, IOS, and Windows 8 phones.

  2. Remove the Attribute data-toggle on the .dropdown a link -- removing this allows the click to work on that toggle.

  3. Wrap the removing attribute in an if statement if no-touch

  4. Wrap the hover script in a no-touch if statement

  5. Have a fallback for touch devices so they can get to the first menu item


DEMO: http://jsbin.com/ejAXoda/1/

Edit: http://jsbin.com/ejAXoda/1/edit


CSS

.touch .mobile-link {display:block;}
.no-touch .mobile-link {display:none}

Script(s)

/* ----- Detect touch or no-touch */
/*  Detects touch support and adds appropriate classes to html and returns a JS object
 *  Copyright (c) 2013 Izilla Partners Pty Ltd
 *  http://www.izilla.com.au
 *  Licensed under the MIT license
 *  https://coderwall.com/p/egbgdw
 */
var supports = (function () {
    var a = document.documentElement,
        b = "ontouchstart" in window || navigator.msMaxTouchPoints;
    if (b) {
        a.className += " touch";
        return {
            touch: true
        }
    } else {
        a.className += " no-touch";
        return {
            touch: false
        }
    }
})();

// -------- DO the stuff only on no-touch devices only

if ($("html").hasClass("no-touch")) {


// ------- REMOVE THE DATA TOGGLE ONLY ON "no-touch" devices and get the link to work
  $('.dropdown > a').removeAttr("data-toggle");  


// Hover dropdown for Bootstrap 3.x wrapped in this no-touch var
    /*
     * Project: Bootstrap Hover Dropdown
     * Author: Cameron Spear
     * Contributors: Mattia Larentis
     *
     * Dependencies: Bootstrap's Dropdown plugin, jQuery
     *
     * A simple plugin to enable Bootstrap dropdowns to active on hover and provide a nice user experience.
     *
     * License: MIT
     *
     * http://cameronspear.com/blog/bootstrap-dropdown-on-hover-plugin/
     */
    (function (e, t, n) {
        if ("ontouchstart" in document) return;
        var r = e();
        e.fn.dropdownHover = function (n) {
            r = r.add(this.parent());
            return this.each(function () {
                var i = e(this),
                    s = i.parent(),
                    o = {
                        delay: 500,
                        instantlyCloseOthers: !0
                    }, u = {
                        delay: e(this).data("delay"),
                        instantlyCloseOthers: e(this).data("close-others")
                    }, a = e.extend(!0, {}, o, n, u),
                    f;
                s.hover(function (n) {
                    if (!s.hasClass("open") && !i.is(n.target)) return !0;
                    a.instantlyCloseOthers === !0 && r.removeClass("open");
                    t.clearTimeout(f);
                    s.addClass("open");
                    s.trigger(e.Event("show.bs.dropdown"))
                }, function () {
                    f = t.setTimeout(function () {
                        s.removeClass("open");
                        s.trigger("hide.bs.dropdown")
                    }, a.delay)
                });
                i.hover(function () {
                    a.instantlyCloseOthers === !0 && r.removeClass("open");
                    t.clearTimeout(f);
                    s.addClass("open");
                    s.trigger(e.Event("show.bs.dropdown"))
                });
                s.find(".dropdown-submenu").each(function () {
                    var n = e(this),
                        r;
                    n.hover(function () {
                        t.clearTimeout(r);
                        n.children(".dropdown-menu").show();
                        n.siblings().children(".dropdown-menu").hide()
                    }, function () {
                        var e = n.children(".dropdown-menu");
                        r = t.setTimeout(function () {
                            e.hide()
                        }, a.delay)
                    })
                })
            })
        };
        e(document).ready(function () {
            e('[data-hover="dropdown"]').dropdownHover()
        })
    })(jQuery, this);

 } //END IF no-touch for hover script & removeAttr for the links to work

SAMPLE HTML with fallback for the link:

 <!-- Static navbar -->
  <div class="navbar navbar-default" role="navigation">
    <div class="navbar-header">
      <button type="button" class="navbar-toggle" data-toggle="collapse" data-target=".navbar-collapse">
        <span class="sr-only">Toggle navigation</span>
        <span class="icon-bar"></span>
        <span class="icon-bar"></span>
        <span class="icon-bar"></span>
      </button>
      <a class="navbar-brand" href="#">Project name</a>
    </div>
    <div class="navbar-collapse collapse">
      <ul class="nav navbar-nav">
        <li class="active"><a href="#">Link</a></li>
        <li><a href="#">Link</a></li>
        <li><a href="#">Link</a></li>
        <li class="dropdown">
          <a href="http://getbootstrap.com" data-toggle="dropdown" data-hover="dropdown" data-delay="1000" data-close-others="false">Blog <b class="caret"></b></a>
          <ul class="dropdown-menu">


            <!-- add for touch they won't be able to get to the link -->
            <li class="mobile-link"><a href="blog.html">Latest News</a></li>

            <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="dropdown-header">Nav header</li>
            <li><a href="#">Separated link</a></li>
            <li><a href="#">One more separated link</a></li>
          </ul>
        </li>
      </ul>
      <ul class="nav navbar-nav navbar-right">
        <li class="active"><a href="./">Default</a></li>
        <li><a href="../navbar-static-top/">Static top</a></li>
        <li><a href="../navbar-fixed-top/">Fixed top</a></li>
      </ul>
    </div><!--/.nav-collapse -->
  </div>

I tested this on Android. Test this on IOS, Windows 8, and other devices before awarding/accepting. Should work smoothly.

like image 108
Christina Avatar answered Oct 15 '22 10:10

Christina


$('body').on('mouseover', '.dropdown-toggle', function(e){
    $(e.currentTarget).trigger('click')
})

or instead of ".dropdown-toggle" you could use the id of the element that triggers the dropdown

like image 30
w3jimmy Avatar answered Oct 15 '22 11:10

w3jimmy