user722951 user722951 - 1 month ago 12
CSS Question

Dropdowns not working in Bootstrap navbar

Building a Bootstrap template for a responsive site. It needs to show a simple horizontal navbar on desktop and tablet, then go to offcanvas slide-in on phones. Found an example by Phil Hughes (iamphill) on Github. As I adapted this, the dropdown menu items stopped working. When I click on either of the two dropdowns nothing happens. No errors in Chrome Inspector. Validating HTML, CSS and JS does not reveal anything. The bug is either too obvious or too subtle.



! function(t) {
"use strict";
"function" == typeof define && define.amd ? define(["jquery"], t) : "object" == typeof exports ? module.exports = t(require("jquery")) : t(jQuery)
}(function(t) {
"use strict";

function e(e) {
var o = e.attr("data-target");
o || (o = e.attr("href"), o = o && /#[A-Za-z]/.test(o) && o.replace(/.*(?=#[^\s]*$)/, ""));
var n = o && t(o);
return n && n.length ? n : e.parent()
}

function o(o) {
o && 3 === o.which || (t(r).remove(), t(a).each(function() {
var n = t(this),
r = e(n),
a = {
relatedTarget: this
};
r.hasClass("open") && (o && "click" == o.type && /input|textarea/i.test(o.target.tagName) && t.contains(r[0], o.target) || (r.trigger(o = t.Event("hide.bs.dropdown", a)), o.isDefaultPrevented() || (n.attr("aria-expanded", "false"), r.removeClass("open").trigger(t.Event("hidden.bs.dropdown", a)))))
}))
}

function n(e) {
return this.each(function() {
var o = t(this),
n = o.data("bs.dropdown");
n || o.data("bs.dropdown", n = new i(this)), "string" == typeof e && n[e].call(o)
})
}
var r = ".dropdown-backdrop",
a = '[data-toggle="dropdown"]',
d = ".drawer-nav",
i = function(e) {
t(e).on("click.bs.dropdown", this.toggle)
};
i.VERSION = "3.3.5", i.prototype.toggle = function(n) {
var r = t(this);
if (!r.is(".disabled, :disabled")) {
var a = e(r),
i = a.hasClass("open");
if (o(), !i) {
"ontouchstart" in document.documentElement && !a.closest(d).length && t(document.createElement("div")).addClass("dropdown-backdrop").insertAfter(t(this)).on("click", o);
var s = {
relatedTarget: this
};
if (a.trigger(n = t.Event("show.bs.dropdown", s)), n.isDefaultPrevented()) return;
r.trigger("focus").attr("aria-expanded", "true"), a.toggleClass("open").trigger(t.Event("shown.bs.dropdown", s))
}
return !1
}
}, i.prototype.keydown = function(o) {
if (/(38|40|27|32)/.test(o.which) && !/input|textarea/i.test(o.target.tagName)) {
var n = t(this);
if (o.preventDefault(), o.stopPropagation(), !n.is(".disabled, :disabled")) {
var r = e(n),
d = r.hasClass("open");
if (!d && 27 != o.which || d && 27 == o.which) return 27 == o.which && r.find(a).trigger("focus"), n.trigger("click");
var i = " li:not(.disabled):visible a",
s = r.find(".dropdown-menu" + i);
if (s.length) {
var p = s.index(o.target);
38 == o.which && p > 0 && p--, 40 == o.which && p < s.length - 1 && p++, ~p || (p = 0), s.eq(p).trigger("focus")
}
}
}
};
var s = t.fn.dropdown;
t.fn.dropdown = n, t.fn.dropdown.Constructor = i, t.fn.dropdown.noConflict = function() {
return t.fn.dropdown = s, this
}, t(document).on("click.bs.dropdown.data-api", o).on("click.bs.dropdown.data-api", ".dropdown form", function(t) {
t.stopPropagation()
}).on("click.bs.dropdown.data-api", a, i.prototype.toggle).on("keydown.bs.dropdown.data-api", a, i.prototype.keydown).on("keydown.bs.dropdown.data-api", ".dropdown-menu", i.prototype.keydown)
});

// and now js for offcanvas
(function() {
var bind = function(fn, me){ return function(){ return fn.apply(me, arguments); }; };

(function($, window) {
var Offcanvas, OffcanvasDropdown, OffcanvasTouch, transformCheck;
OffcanvasDropdown = (function() {
function OffcanvasDropdown(element) {
this.element = element;
this._clickEvent = bind(this._clickEvent, this);
this.element = $(this.element);
this.nav = this.element.closest(".nav");
this.dropdown = this.element.parent().find(".dropdown-menu");
this.element.on('click', this._clickEvent);
this.nav.closest('.navbar-offcanvas').on('click', (function(_this) {
return function() {
if (_this.dropdown.is('.shown')) {
return _this.dropdown.removeClass('shown').closest('.active').removeClass('active');
}
};
})(this));
}

OffcanvasDropdown.prototype._clickEvent = function(e) {
if (!this.dropdown.hasClass('shown')) {
e.preventDefault();
}
e.stopPropagation();
$('.dropdown-toggle').not(this.element).closest('.active').removeClass('active').find('.dropdown-menu').removeClass('shown');
this.dropdown.toggleClass("shown");
return this.element.parent().toggleClass('active');
};

return OffcanvasDropdown;

})();
OffcanvasTouch = (function() {
function OffcanvasTouch(button, element, location, offcanvas) {
this.button = button;
this.element = element;
this.location = location;
this.offcanvas = offcanvas;
this._getFade = bind(this._getFade, this);
this._getCss = bind(this._getCss, this);
this._touchEnd = bind(this._touchEnd, this);
this._touchMove = bind(this._touchMove, this);
this._touchStart = bind(this._touchStart, this);
this.endThreshold = 130;
this.startThreshold = this.element.hasClass('navbar-offcanvas-right') ? $("body").outerWidth() - 60 : 20;
this.maxStartThreshold = this.element.hasClass('navbar-offcanvas-right') ? $("body").outerWidth() - 20 : 60;
this.currentX = 0;
this.fade = this.element.hasClass('navbar-offcanvas-fade') ? true : false;
$(document).on("touchstart", this._touchStart);
$(document).on("touchmove", this._touchMove);
$(document).on("touchend", this._touchEnd);
}

OffcanvasTouch.prototype._touchStart = function(e) {
this.startX = e.originalEvent.touches[0].pageX;
if (this.element.is('.in')) {
return this.element.height($(window).outerHeight());
}
};

OffcanvasTouch.prototype._touchMove = function(e) {
var x;
if ($(e.target).parents('.navbar-offcanvas').length > 0) {
return true;
}
if (this.startX > this.startThreshold && this.startX < this.maxStartThreshold) {
e.preventDefault();
x = e.originalEvent.touches[0].pageX - this.startX;
x = this.element.hasClass('navbar-offcanvas-right') ? -x : x;
if (Math.abs(x) < this.element.outerWidth()) {
this.element.css(this._getCss(x));
return this.element.css(this._getFade(x));
}
} else if (this.element.hasClass('in')) {
e.preventDefault();
x = e.originalEvent.touches[0].pageX + (this.currentX - this.startX);
x = this.element.hasClass('navbar-offcanvas-right') ? -x : x;
if (Math.abs(x) < this.element.outerWidth()) {
this.element.css(this._getCss(x));
return this.element.css(this._getFade(x));
}
}
};

OffcanvasTouch.prototype._touchEnd = function(e) {
var end, sendEvents, x;
if ($(e.target).parents('.navbar-offcanvas').length > 0) {
return true;
}
sendEvents = false;
x = e.originalEvent.changedTouches[0].pageX;
if (Math.abs(x) === this.startX) {
return;
}
end = this.element.hasClass('navbar-offcanvas-right') ? Math.abs(x) > (this.endThreshold + 50) : x < (this.endThreshold + 50);
if (this.element.hasClass('in') && end) {
this.currentX = 0;
this.element.removeClass('in').css(this._clearCss());
this.button.removeClass('is-open');
sendEvents = true;
} else if (Math.abs(x - this.startX) > this.endThreshold && this.startX > this.startThreshold && this.startX < this.maxStartThreshold) {
this.currentX = this.element.hasClass('navbar-offcanvas-right') ? -this.element.outerWidth() : this.element.outerWidth();
this.element.toggleClass('in').css(this._clearCss());
this.button.toggleClass('is-open');
sendEvents = true;
} else {
this.element.css(this._clearCss());
}
return this.offcanvas.bodyOverflow(sendEvents);
};

OffcanvasTouch.prototype._getCss = function(x) {
x = this.element.hasClass('navbar-offcanvas-right') ? -x : x;
return {
"-webkit-transform": "translate3d(" + x + "px, 0px, 0px)",
"-webkit-transition-duration": "0s",
"-moz-transform": "translate3d(" + x + "px, 0px, 0px)",
"-moz-transition": "0s",
"-o-transform": "translate3d(" + x + "px, 0px, 0px)",
"-o-transition": "0s",
"transform": "translate3d(" + x + "px, 0px, 0px)",
"transition": "0s"
};
};

OffcanvasTouch.prototype._getFade = function(x) {
if (this.fade) {
return {
"opacity": x / this.element.outerWidth()
};
} else {
return {};
}
};

OffcanvasTouch.prototype._clearCss = function() {
return {
"-webkit-transform": "",
"-webkit-transition-duration": "",
"-moz-transform": "",
"-moz-transition": "",
"-o-transform": "",
"-o-transition": "",
"transform": "",
"transition": "",
"opacity": ""
};
};

return OffcanvasTouch;

})();
window.Offcanvas = Offcanvas = (function() {
function Offcanvas(element) {
var t, target;
this.element = element;
this.bodyOverflow = bind(this.bodyOverflow, this);
this._sendEventsAfter = bind(this._sendEventsAfter, this);
this._sendEventsBefore = bind(this._sendEventsBefore, this);
this._documentClicked = bind(this._documentClicked, this);
this._close = bind(this._close, this);
this._open = bind(this._open, this);
this._clicked = bind(this._clicked, this);
this._navbarHeight = bind(this._navbarHeight, this);
target = this.element.attr('data-target') ? this.element.attr('data-target') : false;
if (target) {
this.target = $(target);
if (this.target.length && !this.target.hasClass('js-offcanvas-done')) {
this.element.addClass('js-offcanvas-has-events');
this.location = this.target.hasClass("navbar-offcanvas-right") ? "right" : "left";
this.target.addClass(transform ? "offcanvas-transform js-offcanvas-done" : "offcanvas-position js-offcanvas-done");
this.target.data('offcanvas', this);
this.element.on("click", this._clicked);
this.target.on('transitionend', (function(_this) {
return function() {
if (_this.target.is(':not(.in)')) {
return _this.target.height('');
}
};
})(this));
$(document).on("click", this._documentClicked);
if (this.target.hasClass('navbar-offcanvas-touch')) {
t = new OffcanvasTouch(this.element, this.target, this.location, this);
}
this.target.find(".dropdown-toggle").each(function() {
var d;
return d = new OffcanvasDropdown(this);
});
this.target.on('offcanvas.toggle', (function(_this) {
return function(e) {
return _this._clicked(e);
};
})(this));
this.target.on('offcanvas.close', (function(_this) {
return function(e) {
return _this._close(e);
};
})(this));
this.target.on('offcanvas.open', (function(_this) {
return function(e) {
return _this._open(e);
};
})(this));
}
} else {
console.warn('Offcanvas: `data-target` attribute must be present.');
}
}

Offcanvas.prototype._navbarHeight = function() {
if (this.target.is('.in')) {
return this.target.height($(window).outerHeight());
}
};

Offcanvas.prototype._clicked = function(e) {
e.preventDefault();
this._sendEventsBefore();
$(".navbar-offcanvas").not(this.target).trigger('offcanvas.close');
this.target.toggleClass('in');
this.element.toggleClass('is-open');
this._navbarHeight();
return this.bodyOverflow();
};

Offcanvas.prototype._open = function(e) {
e.preventDefault();
if (this.target.is('.in')) {
return;
}
this._sendEventsBefore();
this.target.addClass('in');
this.element.addClass('is-open');
this._navbarHeight();
return this.bodyOverflow();
};

Offcanvas.prototype._close = function(e) {
e.preventDefault();
if (this.target.is(':not(.in)')) {
return;
}
this._sendEventsBefore();
this.target.removeClass('in');
this.element.removeClass('is-open');
this._navbarHeight();
return this.bodyOverflow();
};

Offcanvas.prototype._documentClicked = function(e) {
var clickedEl;
clickedEl = $(e.target);
if (!clickedEl.hasClass('offcanvas-toggle') && clickedEl.parents('.offcanvas-toggle').length === 0 && clickedEl.parents('.navbar-offcanvas').length === 0 && !clickedEl.hasClass('navbar-offcanvas')) {
if (this.target.hasClass('in')) {
e.preventDefault();
this._sendEventsBefore();
this.target.removeClass('in');
this.element.removeClass('is-open');
this._navbarHeight();
return this.bodyOverflow();
}
}
};

Offcanvas.prototype._sendEventsBefore = function() {
if (this.target.hasClass('in')) {
return this.target.trigger('hide.bs.offcanvas');
} else {
return this.target.trigger('show.bs.offcanvas');
}
};

Offcanvas.prototype._sendEventsAfter = function() {
if (this.target.hasClass('in')) {
return this.target.trigger('shown.bs.offcanvas');
} else {
return this.target.trigger('hidden.bs.offcanvas');
}
};

Offcanvas.prototype.bodyOverflow = function(events) {
if (events === null) {
events = true;
}
if (this.target.is('.in')) {
$('body').addClass('offcanvas-stop-scrolling');
} else {
$('body').removeClass('offcanvas-stop-scrolling');
}
if (events) {
return this._sendEventsAfter();
}
};

return Offcanvas;

})();
transformCheck = (function(_this) {
return function() {
var asSupport, el, regex, translate3D;
el = document.createElement('div');
translate3D = "translate3d(0px, 0px, 0px)";
regex = /translate3d\(0px, 0px, 0px\)/g;
el.style.cssText = "-webkit-transform: " + translate3D + "; -moz-transform: " + translate3D + "; -o-transform: " + translate3D + "; transform: " + translate3D;
asSupport = el.style.cssText.match(regex);
return _this.transform = asSupport.length !== null;
};
})(this);
return $(function() {
transformCheck();
$('[data-toggle="offcanvas"]').each(function() {
var oc;
return oc = new Offcanvas($(this));
});
$(window).on('resize', function() {
$('.navbar-offcanvas.in').each(function() {
return $(this).height('').removeClass('in');
});
return $('.offcanvas-toggle').removeClass('is-open');
});
return $('.offcanvas-toggle').each(function() {
return $(this).on('click', function(e) {
var el, selector;
if (!$(this).hasClass('js-offcanvas-has-events')) {
selector = $(this).attr('data-target');
el = $(selector);
if (el) {
el.height('');
el.removeClass('in');
return $('body').css({
overflow: '',
position: ''
});
}
}
});
});
});
})(window.jQuery, window);

}).call(this);

/* CSS used here will be applied after bootstrap.css */
@media (max-width: 767px) {
.offcanvas-stop-scrolling {
height: 100%;
overflow: hidden; }
.navbar-default .navbar-offcanvas {
background-color: #f8f8f8; }
.navbar-inverse .navbar-offcanvas {
background-color: #222; }
.navbar-offcanvas {
position: fixed;
width: 100%;
max-width: 250px;
left: -250px;
top: 0;
padding-left: 15px;
padding-right: 15px;
z-index: 999;
overflow: scroll;
-webkit-overflow-scrolling: touch;
-webkit-transition: all 0.15s ease-in;
transition: all 0.15s ease-in; }
.navbar-offcanvas.in {
box-shadow: 0 0 20px rgba(0, 0, 0, 0.3); }
.navbar-offcanvas.navbar-offcanvas-fade {
opacity: 0; }
.navbar-offcanvas.navbar-offcanvas-fade.in {
opacity: 1; }
.navbar-offcanvas.offcanvas-transform.in {
-webkit-transform: translateX(250px);
transform: translateX(250px); }
.navbar-offcanvas.offcanvas-position.in {
left: 0; }
.navbar-offcanvas.navbar-offcanvas-right {
left: auto;
right: -250px; }
.navbar-offcanvas.navbar-offcanvas-right.offcanvas-transform.in {
-webkit-transform: translateX(-250px);
transform: translateX(-250px); }
.navbar-offcanvas.navbar-offcanvas-right.offcanvas-position.in {
left: auto;
right: 0; }
.navbar-offcanvas .dropdown.active .caret {
border-top: 0;
border-bottom: 4px solid; }
.navbar-offcanvas .dropdown-menu {
position: relative;
width: 100%;
border: inherit;
box-shadow: none;
-webkit-transition: height 0.15s ease-in;
transition: height 0.15s ease-in; }
.navbar-offcanvas .dropdown-menu.shown {
display: block;
margin-bottom: 10px; } }

.offcanvas-toggle .icon-bar {
background: #000;
-webkit-transition: all .25s ease-in-out;
transition: all .25s ease-in-out; }

.offcanvas-toggle.is-open .icon-bar:nth-child(1) {
-webkit-transform: rotate(45deg) translate(5px, 4px);
transform: rotate(45deg) translate(5px, 4px); }

.offcanvas-toggle.is-open .icon-bar:nth-child(2) {
opacity: 0; }

.offcanvas-toggle.is-open .icon-bar:nth-child(3) {
-webkit-transform: rotate(-45deg) translate(4px, -4px);
transform: rotate(-45deg) translate(4px, -4px); }

<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.0/jquery.min.js"></script>
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css" integrity="sha384-BVYiiSIFeK1dGmJRAkycuHAHRg32OmUcww7on3RYdg4Va+PmSTsz/K68vbdEjh4u" crossorigin="anonymous">

<!-- Optional theme -->
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap-theme.min.css" integrity="sha384-rHyoN1iRsVXV4nD0JutlnGaslCJuC7uwjduW9SVrLvRYooPp2bWYgmgJQIXwl/Sp" crossorigin="anonymous">

<!-- Latest compiled and minified JavaScript -->
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/js/bootstrap.min.js" integrity="sha384-Tc5IQib027qvyjSMfHjOMaLkfuWVxZxUPnCJA7l2mCWNIpG9mGCD8wGNIcPD7Txa" crossorigin="anonymous"></script>

<body class="body-offcanvas">
<header class="clearfix">
<nav class="navbar navbar-default">
<div class="container-fluid">
<div class="navbar-header">
<button type="button" class="navbar-toggle offcanvas-toggle" data-toggle="offcanvas" data-target="#js-bootstrap-offcanvas">
<span class="icon-bar"></span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
</button>
<a class="navbar-brand" href="#">Brandhere</a>
</div>
<div class="navbar-offcanvas navbar-offcanvas-touch" id="js-bootstrap-offcanvas">
<ul class="nav navbar-nav">
<li class="dropdown">
<a class="dropdown-toggle" data-toggle="dropdown" href="#">NUMBERS<span class="caret"></span></a>
<ul class="dropdown-menu">
<li><a href="1.html">One</a></li>
<li><a href="2.html">Two</a></li>
<li><a href="36.html">Thirty-six</a></li>
<li><a href="minus7.html">-7</a></li>
<li><a href="18.html">Eighteen</a></li>
</ul>
</li>
<li class="dropdown">
<a class="dropdown-toggle" data-toggle="dropdown" href="#">MUSIC<span class="caret"></span></a>
<ul class="dropdown-menu">
<li><a href="bj-cole.html">BJ Cole</a></li>
<li><a href="claude-debussy.html">C. Debussy</a></li>
<li><a href="brian-eno.html">Brian Eno</a></li>
<li><a href="robert-fripp.html">Robert Fripp</a></li>
<li><a href="skip-james.html">Skip James</a></li>
</ul>
</li>
</ul>
</div>
</div>
</nav>
</header>

<div class="container">
<div class="row">
<div>
<h1>Page Title</h1>
<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Proin feugiat hendrerit feugiat. In cursus nisl id arcu ullamcorper, eget euismod ante tincidunt. Aliquam tincidunt felis eget quam euismod cursus. Nam aliquet a tellus ut pretium. Pellentesque fermentum nulla tempus mauris sagittis, eget imperdiet quam tristique. Pellentesque quis mauris mauris. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Praesent sodales turpis fringilla ligula rutrum, eget mattis justo bibendum. Integer imperdiet mi non cursus bibendum. Nullam vitae cursus justo. Integer quis elit sit amet arcu pellentesque sit amet a sapien. Aliquam tincidunt felis eget quam euismod cursus. Suspendisse lobortis ut elit vitae rhoncus. Ut tincidunt, ante eu egestas sodales, dui nulla aliquet mi, a eleifend lacus risus sit amet lacus.</p>
</div>
</div>
</div>
</body>





Here it is on Bootply http://www.bootply.com/ONyk2E5GWv

Answer

There are 2 things here:
1) You're using same class for dropdown-toggle for both Numbers as well as Music. Try to keep it unique like below -

<li class="dropdown numbers">
  <a class="dropdown-toggle" data-toggle="numbers" href="#">NUMBERS<span class="caret"></span></a>
  <ul class="dropdown-menu">
    <li><a href="1.html">One</a></li>
  </ul>
</li>
<li class="dropdown music">
  <a class="dropdown-toggle" data-toggle="music" href="#">MUSIC<span class="caret"></span></a>
  <ul class="dropdown-menu">
    <li><a href="bj-cole.html">BJ Cole</a></li>
  </ul>
</li>

2) You're using CSS Media Query max-width: 767px which means that this styling is applied only for screens whose width are less than 767 pixels, ideally Tablets and Mobile devices. Upon click of dropdown, on the dropdown-menu, 'shown' class is being added which will have the styling of displaying the list by changing the CSS attribute display from 'none' to 'block'

.navbar-offcanvas .dropdown-menu.shown {
   display: block;
   margin-bottom: 10px;
}

Comments