'Custom responsive navbar (priority nav) using Bootstrap 5 and no JQuery
Trying to create a Bootstrap 5 custom responsive navbar (priority nav) with a "show More..." option using Vanilla JS, as I have dozens of menu-items and I can't use jQuery
As you might know, bootstrap navbars doesn't adopt to the screen widths and it gets broken into the next line introduced by overflowing menus. I want to stop the menu overflow to the next line by having them move to the "More..." menu-item using bootstrap 5 and Vanilla Javascript
custom responsive navbar mockup
I did try to modify this answer but had no luck, as it's written with Bootstrap 3 and uses JQuery, which I can't use
var elemWidth, fitCount, varWidth = 0,
ctr,
$menu = $("ul#menu"),
$collectedSet;
ctr = $menu.children().length;
$menu.children().each(function() {
varWidth += $(this).outerWidth();
});
collect();
$(window).resize(collect);
function collect() {
elemWidth = $menu.width();
fitCount = Math.floor((elemWidth / varWidth) * ctr) - 1;
$menu.children().css({
"display": "block",
"width": "auto"
});
$collectedSet = $menu.children(":gt(" + fitCount + ")");
$("#submenu").empty().append($collectedSet.clone());
$collectedSet.css({
"display": "none",
"width": "0"
});
}
* {
box-sizing: border-box;
margin: 0;
padding: 0;
}
div.menuwrap {
position: relative;
background-color: #ccc;
height: 48px;
overflow: visible;
}
ul.menu {
height: 48px;
max-width: 80%;
overflow: hidden;
}
ul.menu>li {
display: block;
float: left;
height: auto;
white-space: nowrap;
padding: 4px 8px;
}
ul.collect {
position: absolute;
right: 0;
top: 0;
padding: 4px 8px;
overflow: visible;
}
ul.collect ul.dropdown-menu {
right: 0;
left: auto;
}
<script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/js/bootstrap.bundle.min.js"></script>
<link href="https://cdn.jsdelivr.net/npm/[email protected]/dist/css/bootstrap.min.css" rel="stylesheet" />
<div class="menuwrap">
<ul id="menu" class="nav nav-pills menu">
<li class="active"><a href="#">Dashboard</a></li>
<li><a href="#">Docs</a></li>
<li><a href="#">Docs 2</a></li>
<li><a href="#">Docs 3</a></li>
<li><a href="#">Docs 4</a></li>
<li><a href="#">Data</a></li>
<li><a href="#">iWeb</a></li>
<li><a href="#">Program</a></li>
</ul>
<ul class="nav nav-pills collect">
<li class="dropdown">
<a role="button" href="#" data-toggle="dropdown" class="dropdown-toggle">
More <span class="caret"></span>
</a>
<ul id="submenu" class="dropdown-menu"></ul>
</li>
</ul>
</div>
Solution 1:[1]
In case anyone had the same issue, I managed to do it in this jsfiddle using the Priority Nav plugin
// https://gijsroge.github.io/priority-nav.js/
/*
* priority-nav - v1.0.11 | (c) 2016 @gijsroge | MIT license
* Repository: https://github.com/gijsroge/priority-navigation.git
* Description: Priority+ pattern navigation that hides menu items if they don't fit on screen.
* Demo: http://gijsroge.github.io/priority-nav.js/
*/
! function(a, b) {
"function" == typeof define && define.amd ? define("priorityNav", b(a)) : "object" == typeof exports ? module.exports = b(a) : a.priorityNav = b(a)
}(window || this, function(a) {
"use strict";
function b(a, b, c) {
var d;
return function() {
var e = this,
f = arguments,
g = function() {
d = null, c || a.apply(e, f)
},
h = c && !d;
clearTimeout(d), d = setTimeout(g, b), h && a.apply(e, f)
}
}
var c, d, e, f, g, h, i, j, k, l = {},
m = [],
n = !!document.querySelector && !!a.addEventListener,
o = {},
p = 0,
q = 0,
r = 0,
s = {
initClass: "js-priorityNav",
mainNavWrapper: "nav",
mainNav: "ul",
navDropdownClassName: "nav__dropdown",
navDropdownToggleClassName: "nav__dropdown-toggle",
navDropdownLabel: "...",
navDropdownBreakpointLabel: "menu",
breakPoint: 500,
throttleDelay: 50,
offsetPixels: 0,
count: !0,
moved: function() {},
movedBack: function() {}
},
t = function(a, b, c) {
if ("[object Object]" === Object.prototype.toString.call(a))
for (var d in a) Object.prototype.hasOwnProperty.call(a, d) && b.call(c, a[d], d, a);
else
for (var e = 0, f = a.length; f > e; e++) b.call(c, a[e], e, a)
},
u = function(a, b) {
for (var c = b.charAt(0); a && a !== document; a = a.parentNode)
if ("." === c) {
if (a.classList.contains(b.substr(1))) return a
} else if ("#" === c) {
if (a.id === b.substr(1)) return a
} else if ("[" === c && a.hasAttribute(b.substr(1, b.length - 2))) return a;
return !1
},
v = function(a, b) {
var c = {};
return t(a, function(b, d) {
c[d] = a[d]
}), t(b, function(a, d) {
c[d] = b[d]
}), c
},
w = function(a, b) {
if (a.classList) a.classList.toggle(b);
else {
var c = a.className.split(" "),
d = c.indexOf(b);
d >= 0 ? c.splice(d, 1) : c.push(b), a.className = c.join(" ")
}
},
x = function(a, b) {
return k = document.createElement("span"), h = document.createElement("ul"), i = document.createElement("button"), i.innerHTML = b.navDropdownLabel, i.setAttribute("aria-controls", "menu"), h.setAttribute("aria-hidden", "true"), a.querySelector(g).parentNode !== a ? void console.warn("mainNav is not a direct child of mainNavWrapper, double check please") : (a.insertAfter(k, a.querySelector(g)), k.appendChild(i), k.appendChild(h), h.classList.add(b.navDropdownClassName), h.classList.add("priority-nav__dropdown"), i.classList.add(b.navDropdownToggleClassName), i.classList.add("priority-nav__dropdown-toggle"), k.classList.add(b.navDropdownClassName + "-wrapper"), k.classList.add("priority-nav__wrapper"), void a.classList.add("priority-nav"))
},
y = function(a) {
var b = window.getComputedStyle(a),
c = parseFloat(b.paddingLeft) + parseFloat(b.paddingRight);
return a.clientWidth - c
},
z = function() {
var a = document,
b = window,
c = a.compatMode && "CSS1Compat" === a.compatMode ? a.documentElement : a.body,
d = c.clientWidth,
e = c.clientHeight;
return b.innerWidth && d > b.innerWidth && (d = b.innerWidth, e = b.innerHeight), {
width: d,
height: e
}
},
A = function(a) {
e = y(a), j = a.querySelector(h).parentNode === a ? a.querySelector(h).offsetWidth : 0, f = E(a) + o.offsetPixels, r = z().width
};
l.doesItFit = function(a) {
o = v(s, c || {});
var d = 0 === a.getAttribute("instance") ? d : o.throttleDelay;
p++, b(function() {
var b = a.getAttribute("instance");
for (A(a); f >= e && a.querySelector(g).children.length > 0 || r < o.breakPoint && a.querySelector(g).children.length > 0;) l.toDropdown(a, b), A(a, b), r < o.breakPoint && D(a, b, o.navDropdownBreakpointLabel);
for (; e >= m[b][m[b].length - 1] && r > o.breakPoint;) l.toMenu(a, b), r > o.breakPoint && D(a, b, o.navDropdownLabel);
m[b].length < 1 && (a.querySelector(h).classList.remove("show"), D(a, b, o.navDropdownLabel)), a.querySelector(g).children.length < 1 ? (a.classList.add("is-empty"), D(a, b, o.navDropdownBreakpointLabel)) : a.classList.remove("is-empty"), B(a, b)
}, d)()
};
var B = function(a, b) {
m[b].length < 1 ? (a.querySelector(i).classList.add("priority-nav-is-hidden"), a.querySelector(i).classList.remove("priority-nav-is-visible"), a.classList.remove("priority-nav-has-dropdown"), a.querySelector(".priority-nav__wrapper").setAttribute("aria-haspopup", "false")) : (a.querySelector(i).classList.add("priority-nav-is-visible"), a.querySelector(i).classList.remove("priority-nav-is-hidden"), a.classList.add("priority-nav-has-dropdown"), a.querySelector(".priority-nav__wrapper").setAttribute("aria-haspopup", "true"))
},
C = function(a, b) {
a.querySelector(i).setAttribute("priorityNav-count", m[b].length)
},
D = function(a, b, c) {
a.querySelector(i).innerHTML = c
};
l.toDropdown = function(a, b) {
a.querySelector(h).firstChild && a.querySelector(g).children.length > 0 ? a.querySelector(h).insertBefore(a.querySelector(g).lastElementChild, a.querySelector(h).firstChild) : a.querySelector(g).children.length > 0 && a.querySelector(h).appendChild(a.querySelector(g).lastElementChild), m[b].push(f), B(a, b), a.querySelector(g).children.length > 0 && o.count && C(a, b), o.moved()
}, l.toMenu = function(a, b) {
a.querySelector(h).children.length > 0 && a.querySelector(g).appendChild(a.querySelector(h).firstElementChild), m[b].pop(), B(a, b), a.querySelector(g).children.length > 0 && o.count && C(a, b), o.movedBack()
};
var E = function(a) {
for (var b = a.childNodes, c = 0, d = 0; d < b.length; d++) 3 !== b[d].nodeType && (isNaN(b[d].offsetWidth) || (c += b[d].offsetWidth));
return c
},
F = function(a, b) {
window.attachEvent ? window.attachEvent("onresize", function() {
l.doesItFit && l.doesItFit(a)
}) : window.addEventListener && window.addEventListener("resize", function() {
l.doesItFit && l.doesItFit(a)
}, !0), a.querySelector(i).addEventListener("click", function() {
w(a.querySelector(h), "show"), w(this, "is-open"), w(a, "is-open"), -1 !== a.className.indexOf("is-open") ? a.querySelector(h).setAttribute("aria-hidden", "false") : (a.querySelector(h).setAttribute("aria-hidden", "true"), a.querySelector(h).blur())
}), document.addEventListener("click", function(c) {
u(c.target, "." + b.navDropdownClassName) || c.target === a.querySelector(i) || (a.querySelector(h).classList.remove("show"), a.querySelector(i).classList.remove("is-open"), a.classList.remove("is-open"))
}), document.onkeydown = function(a) {
a = a || window.event, 27 === a.keyCode && (h.classList.remove("show"), i.classList.remove("is-open"), d.classList.remove("is-open"))
}
};
Element.prototype.remove = function() {
this.parentElement.removeChild(this)
}, NodeList.prototype.remove = HTMLCollection.prototype.remove = function() {
for (var a = 0, b = this.length; b > a; a++) this[a] && this[a].parentElement && this[a].parentElement.removeChild(this[a])
}, l.destroy = function() {
o && (document.documentElement.classList.remove(o.initClass), k.remove(), o = null, delete l.init, delete l.doesItFit)
}, n && "undefined" != typeof Node && (Node.prototype.insertAfter = function(a, b) {
this.insertBefore(a, b.nextSibling)
});
var G = function(a) {
var b = a.charAt(0);
return "." === b || "#" === b ? !1 : !0
};
return l.init = function(a) {
if (o = v(s, a || {}), !n && "undefined" == typeof Node) return void console.warn("This browser doesn't support priorityNav");
if (!G(o.navDropdownClassName) || !G(o.navDropdownToggleClassName)) return void console.warn("No symbols allowed in navDropdownClassName & navDropdownToggleClassName. These are not selectors.");
var b = document.querySelectorAll(o.mainNavWrapper);
t(b, function(a) {
return m[q] = [], a.setAttribute("instance", q++), (d = a) ? (g = o.mainNav, a.querySelector(g) ? (x(a, o), h = "." + o.navDropdownClassName, a.querySelector(h) ? (i = "." + o.navDropdownToggleClassName, a.querySelector(i) ? (F(a, o), void l.doesItFit(a)) : void console.warn("couldn't find the specified navDropdownToggle element")) : void console.warn("couldn't find the specified navDropdown element")) : void console.warn("couldn't find the specified mainNav element")) : void console.warn("couldn't find the specified mainNavWrapper element")
}), p++, document.documentElement.classList.add(o.initClass)
}, l
});
var nav = priorityNav.init();
/*
* Core styles for PriorityNav.js
* These styles are not optional and should always be included
*
* Free to use under the MIT License.
* http://twitter.com/GijsRoge
*/
.priority-nav {
white-space: nowrap;
/*
* Makes sure the menu's are inline-block so they don't take up
* the entire width of its parent. This will break the plugin.
*/
}
.priority-nav ul {
display: inline-block;
}
.priority-nav li {
display: inline-block;
}
.priority-nav-has-dropdown .priority-nav__dropdown-toggle {
position: relative;
}
.priority-nav__wrapper {
position: relative;
}
.priority-nav__dropdown {
position: absolute;
visibility: hidden;
}
.priority-nav__dropdown.show {
visibility: visible;
}
.priority-nav__dropdown-toggle {
visibility: hidden;
position: absolute;
}
.priority-nav-is-visible {
visibility: visible;
}
.priority-nav-is-hidden {
visibility: hidden;
}
/* klk */
nav {
margin: 7rem 0;
padding: 0 4rem;
min-width: 250px;
position: relative;
white-space: nowrap;
max-width: 950px;
-webkit-animation: resize 4s 1 cubic-bezier(0.4, 0, 0.2, 1);
animation: resize 4s 1 cubic-bezier(0.4, 0, 0.2, 1);
-webkit-animation-delay: 1s;
animation-delay: 1s;
}
@media (max-width: 650px) {
nav {
padding: 0;
min-width: 100px;
}
nav .wrapper {
padding: 0 1rem;
}
}
nav ul {
display: inline-block;
list-style-type: none;
padding: 0;
margin: 0;
}
nav li {
display: inline-block;
}
nav li:first-child a {
padding-left: 0;
}
@media (max-width: 650px) {
nav li:first-child a {
padding-left: 0.5rem;
}
}
nav a {
display: inline-block;
padding: 4rem 2rem;
font-weight: 700;
}
@media (max-width: 650px) {
nav a {
padding: 2rem 1rem;
}
}
nav .knob {
cursor: ew-resize;
position: absolute;
right: 0;
top: 50%;
-webkit-transform: translateY(-50%) translateX(50%);
transform: translateY(-50%) translateX(50%);
}
@media (max-width: 1000px) {
nav .knob {
display: none;
}
}
.nav__dropdown {
padding: 2rem;
white-space: nowrap;
top: 80%;
right: 0;
background-color: #404040;
transition: 300ms cubic-bezier(0.25, 2, 0.25, 1);
-webkit-transform-origin: center top;
transform-origin: center top;
-webkit-transform: rotateX(-30deg);
transform: rotateX(-30deg);
opacity: 0;
}
.nav__dropdown.show {
-webkit-transform: rotateX(0deg);
transform: rotateX(0deg);
opacity: 1;
visibility: visible;
box-shadow: 0 0 20px 0 rgba(49, 49, 49, 0.25);
transition: 300ms cubic-bezier(0.25, 2, 0.25, 1), box-shadow 1000ms cubic-bezier(0.25, 2, 0.25, 1);
}
.nav__dropdown a:focus {
box-shadow: 0 0 3px white, inset 0 0 3px white;
}
@media (max-width: 650px) {
.nav__dropdown {
right: auto;
left: -50vw;
}
.nav__dropdown:after {
left: auto;
}
}
.nav__dropdown:after {
content: "";
display: block;
position: absolute;
height: 0;
width: 0;
border-bottom: 6px solid #068df6;
border-left: 6px solid transparent;
border-right: 6px solid transparent;
content: "";
top: -6px;
right: 4rem;
}
.nav__dropdown-wrapper {
display: inline-block;
-webkit-perspective: 500px;
perspective: 500px;
background-color: black;
}
@media (max-width: 650px) {
.nav__dropdown-wrapper {
position: static !important;
}
}
.nav__dropdown li {
display: block;
}
.nav__dropdown li:first-child a {
padding-left: 2rem;
}
.nav__dropdown a {
display: inline-block;
padding: 0.5rem 2rem;
font-weight: 400;
}
nav {
max-width: 100%;
background-color: #404040;
}
.nav-link {
color: white;
font-family: Roboto, Arial, sans-serif;
font-size: 1rem;
font-weight: 1400;
line-height: 1.428571429;
margin: 0;
text-align: left;
background-color: #404040;
line-height: 1.42857143;
padding: 0;
}
.be-top-header .navbar-nav>li.nav-item>a.nav-link:hover {
color: #c2c2c2;
}
.be-top-header .navbar-nav>li.nav-item.show>a:hover {
color: #4285f4;
}
.be-color-header .be-top-header .navbar-collapse ul li a:hover,
.be-color-header .be-sub-navigation .navbar-collapse ul li a:hover i {
color: #545a58;
}
.menu_nav_bar_custom .navbar-nav>li.nav-item>a.nav-link {
padding: 0.2rem 15px;
}
.be-top-header .navbar-nav>li.nav-item.show>a,
.be-sub-navigation .navbar-nav>li.nav-item.show>a:focus {
color: white;
}
@media only screen and (min-width: 992px) {
.navbar {
padding: 1;
}
.navbar .navbar-brand {
padding: 0 0.7em;
}
.navbar .navbar-nav .nav-link {
padding: 1em 0;
}
.navbar .navbar-nav .nav-item {
margin: 0 1em;
}
}
.navbar .navbar-nav .nav-item {
position: relative;
}
.navbar .navbar-nav .nav-item::after {
position: absolute;
bottom: 0;
left: 0;
right: 0;
margin: auto;
background-color: #c2c2c2;
width: 0%;
content: "";
height: 3px;
}
.navbar .navbar-nav .nav-item:hover::after {
width: 100%;
}
.dropdown-menu {
position: absolute !important;
}
.nav-link {
padding: 0.5rem 0.5rem;
}
.dropdown-menu {
position: absolute !important;
}
.nav-link {
padding: 0.5rem 0.5rem;
}
<script src="https://raw.githubusercontent.com/gijsroge/priority-navigation/master/dist/priority-nav.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/bootstrap/5.1.3/js/bootstrap.min.js"></script>
<link href="https://cdn.jsdelivr.net/npm/[email protected]/dist/css/bootstrap.min.css" rel="stylesheet" />
<nav class="navbar navbar-expand fixed-top be-top-header top_nav_bar_custom">
<ul class="mr-auto">
<li class="nav-item">
<a class="nav-link active" aria-current="page" href="#">Home</a>
</li>
<li class="nav-item">
<a class="nav-link" href="#">Features</a>
</li>
<li class="nav-item">
<a class="nav-link" href="#">Pricing</a>
</li>
<li class="nav-item dropdown">
<a class="nav-link dropdown-toggle" href="#" id="navbarDropdownMenuLink" role="button" data-bs-toggle="dropdown" aria-expanded="false">
Dropdown link
</a>
<ul class="dropdown-menu" aria-labelledby="navbarDropdownMenuLink">
<li><a class="dropdown-item" href="#">Action</a></li>
<li><a class="dropdown-item" href="#">Another action</a></li>
<li><a class="dropdown-item" href="#">Something else here</a></li>
</ul>
</nav>
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
Solution | Source |
---|---|
Solution 1 |