<link href="//maxcdn.bootstrapcdn.com/bootstrap/3.3.0/css/bootstrap.min.css" rel="stylesheet" id="bootstrap-css">
<script src="//maxcdn.bootstrapcdn.com/bootstrap/3.3.0/js/bootstrap.min.js"></script>
<script src="//code.jquery.com/jquery-1.11.1.min.js"></script>
<!------ Include the above in your HEAD tag ---------->
<nav class="navbar navbar-default navbar-fixed-top">
<div class="container-fluid">
<ul class="nav navbar-nav" data-toggle="collapse-nav" data-target="#more-menu-1" data-width-offset="150">
<li class="sticky"><a href="#">Link 1</a></li>
<li><a href="#">Link 2</a></li>
<li><a href="#">Link 3</a></li>
<li><a href="#">Link 4</a></li>
<li><a href="#">Sticky Link</a></li>
<li><a href="#">Link 6</a></li>
<li><a href="#">Link 7</a></li>
<li><a href="#">Link 8</a></li>
<li><a href="#">Link 9</a></li>
<li><a href="#">Link 10</a></li>
<li><a href="#">Link 11</a></li>
<li><a href="#">Link 12</a></li>
<li><a href="#">Link 13</a></li>
<li><a href="#">Link 14</a></li>
<li><a href="#">Link 15</a></li>
<!-- Target element @see data-target above,
can contain markup alreadu ie. <a href="#" class="dropdown-toggle" data-toggle="dropdown">More <span class="caret"></span></a> & <ul class="dropdown-menu"></ul>
if required elements are missing they will be created -->
<li id="more-menu-1" class="dropdown"></li>
</ul>
</div><!-- /.navbar-collapse -->
</div><!-- /.container-fluid -->
</nav>
.collapse-nav:before,
.collapse-nav:after {
content: " ";
display: table;
}
.collapse-nav:after {
clear: both;
}
.collapse-nav .navbar-brand,
.collapse-nav.navbarnav > li > a {
padding: 15px;
}
.collapse-nav .collapse-item {
float: left !important;
}
.collapse-item.collapse-item-hidden {
/** .collapse-item-hidden is applied when item is hidden from view, could tweak this and add CSS transition effect **/
display: none;
}
.collapse-nav-target .collapse-item {
float: none !important;
}
.collapse-nav-target .dropdown-menu {
position: absolute !important;
background: white !important;
-webkit-background-clip: padding-box !important;
background-clip: padding-box !important;
border: 1px solid #ccc !important;
border: 1px solid rgba(0, 0, 0, 0.15) !important;
border-radius: 0 !important;
-webkit-box-shadow: 0 6px 12px rgba(0, 0, 0, 0.175) !important;
box-shadow: 0 6px 12px rgba(0, 0, 0, 0.175) !important;
right: 0 !important;
left: auto !important;
margin-top: 0 !important;
}
.collapse-nav-target .dropdown-menu > li > a {
color: #777 !important;
}
.collapse-nav-target .dropdown-menu > li > a:hover {
background-color: #f5f5f5 !important;
}
// Global variables
var collapseNavSelector = $('[data-toggle="collapse-nav"]'),
collapseNavStickyClass = 'sticky';
// Custom function
// Read collapseNav data- & find elements, return data in neat object
// =========================
function collapseNavGetData(target) {
// collapseNavTarget
var collapseNavTarget = target.data('target') || null;
collapseNavTarget = $(collapseNavTarget);
// Check target exists
if (collapseNavTarget.size() === 0) {
return false;
}
collapseNavTarget.addClass('collapse-nav-target').addClass('dropdown');
if (target.find(target.data('target')).size() > 0) {
collapseNavTarget.addClass('sticky');
}
// collapseNavItems
var collapseNavItems = 'li';
var collapseNavItemsNoSticky = target.find('> ' + collapseNavItems).not('.' + collapseNavStickyClass);
collapseNavItems = target.find('> ' + collapseNavItems);
// collapseNavParent
var collapseNavParent = target.data('parent') || '.navbar';
collapseNavParent = target.parents(collapseNavParent);
// collapseNavWidthOffset & parent
// Can be value or selectors of elements
var collapseNavWidthOffset = target.data('width-offset');
var data = {
collapseNav: target, // the data-toggle="collapse-nav" element
collapseNavParent: collapseNavParent,
collapseNavTarget: collapseNavTarget, // object of more menu target where items are moved to
collapseNavTargetMenu: collapseNavTarget.find('.dropdown-menu'),
collapseNavItems: collapseNavItems, // object of items within collapseNav to collapse, override with data-items="li"
collapseNavItemsNoSticky: collapseNavItemsNoSticky, // object of items within collapseNav to collapse, override with data-items="li"
collapseNavItemsSticky: target.find('> ' + '.' + collapseNavStickyClass), // object of sticky items within collapseNav
collapseNavCollapseWidth: target.data('collapse-width') || 300, // a pixel width where the collapseNav should be fully collapse ie. on mobile
collapseNavWidthOffset: collapseNavWidthOffset || 0, // offset for width calculation, can be value or selectors of elements
collapseNavWidth: 0 // collapseNav width based on space available
};
return data;
}
// Custom function
// Calculates collapseNav element width
// =========================
function collapseNavGetWidth(data) {
var collapseNavParentWidth = data.collapseNavParent.width(),
collapseNavWidth = 0, // fallback, will trigger collapse
collapseNavParentMargins = {
'left': parseInt(data.collapseNavParent.css('margin-left')),
'right': parseInt(data.collapseNavParent.css('margin-right'))
},
collapseNavOutterSpace = {
'margin-left': parseInt(data.collapseNav.css('margin-left')),
'margin-right': parseInt(data.collapseNav.css('margin-right')),
'padding-left': parseInt(data.collapseNav.css('padding-left')),
'padding-right': parseInt(data.collapseNav.css('padding-right'))
};
// Check for negative margins on parent
if (collapseNavParentMargins.left < 0 || collapseNavParentMargins.right < 0) {
collapseNavParentWidth = data.collapseNavParent.outerWidth(true);
}
// Check for padding & margins on trigger
$.each(collapseNavOutterSpace, function(a, v) {
collapseNavParentWidth -= v;
});
// Otherwise calculate width base on elements within
if (collapseNavParentWidth > 0) {
collapseNavWidth = collapseNavParentWidth;
// Process width offset
if (data.collapseNavParent.find(data.collapseNavWidthOffset).size() > 0) {
// Offset with element width(s) ie. other navbar elements with parent
data.collapseNavParent.find(data.collapseNavWidthOffset).each(function() {
collapseNavWidth -= $(this).outerWidth(true);
});
}
else {
// Offset with value
collapseNavWidth -= data.collapseNavWidthOffset;
}
// minus sticky items
data.collapseNavItemsSticky.each(function() {
collapseNavWidth -= $(this).outerWidth(true);
});
if (collapseNavWidth <= 0 || collapseNavWidth <= data.collapseNavCollapseWidth) {
collapseNavWidth = 0;
}
}
return collapseNavWidth;
}
// Custom function that resizes menu
// =========================
function collapseNavResize(data) {
var collapseItemsWidth = 0;
// See how many "items" fit inside collapseNavWidth
if (data.collapseNavWidth > 0 ) {
data.collapseNavItemsNoSticky.each(function() {
var collapseNavItem = $(this),
collapseNavItemId = '.' + collapseNavItem.data('collapse-item-id');
collapseItemsWidth += collapseNavItem.outerWidth(true);
if (data.collapseNavWidth < collapseItemsWidth) {
data.collapseNav.find(collapseNavItemId).addClass('collapse-item-hidden');
data.collapseNavTargetMenu.find(collapseNavItemId).removeClass('collapse-item-hidden');
}
else {
data.collapseNav.find(collapseNavItemId).removeClass('collapse-item-hidden');
data.collapseNavTargetMenu.find(collapseNavItemId).addClass('collapse-item-hidden');
}
});
}
else {
// Assume all collapsed
data.collapseNavItemsNoSticky.addClass('collapse-item-hidden');
data.collapseNavTargetMenu.find('.collapse-item').removeClass('collapse-item-hidden');
data.collapseNav.width('auto');
}
// see if collapseNavTarget contains visible elements, :visible selector fails
var visibleItems = data.collapseNavTargetMenu.find('.collapse-item').filter(function() {
return $(this).css('display') !== 'none';
}).size();
if (visibleItems > 0) {
data.collapseNavTarget.show();
}
else {
data.collapseNavTarget.hide();
}
}
// Run through all collapse-nav elements
// =========================
function collapseNavTrigger(setup) {
collapseNavSelector.each(function() {
var collapseNav = $(this),
collapseNavData = collapseNavGetData(collapseNav);
if (collapseNavData === false) {
// No target so bail
return false;
}
// Run setup only on first run
// ---------------------------
if (setup === true) {
// Check target has <ul class="dropdown-menu"></ul> & data-toggle elements, if not create them
if (collapseNavData.collapseNavTarget.find('[data-toggle="dropdown"]').size() === 0) {
$('<a href="#" class="dropdown-toggle" data-toggle="dropdown">More <span class="caret"></span></a>').appendTo(collapseNavData.collapseNavTarget);
}
if (collapseNavData.collapseNavTarget.find('.dropdown-menu').size() === 0) {
collapseNavData.collapseNavTargetMenu = $('<ul class="dropdown-menu"></ul>');
collapseNavData.collapseNavTargetMenu.appendTo(collapseNavData.collapseNavTarget);
}
// clone $collapseNav > collapseNavItems into collapseNavTarget
collapseNavData.collapseNavItems.each(function(i) {
var collapseItem = $(this);
collapseItem.addClass('collapse-item');
if (!collapseItem.hasClass(collapseNavStickyClass)) {
// Add identifier & class to each non-sticky item
collapseItem.data('collapse-item-id', 'collapse-item-' + i).addClass('collapse-item-' + i);
collapseItem.clone().appendTo(collapseNavData.collapseNavTargetMenu);
}
});
collapseNavData.collapseNav.addClass('collapse-nav');
}
// Calulate navbar width
// ---------------------------
collapseNavData.collapseNavWidth = collapseNavGetWidth(collapseNavData);
// Trigger menu resizing
// ---------------------------
collapseNavResize(collapseNavData);
});
}
// Run on doc ready
// =========================
$(document).ready(function(){
collapseNavTrigger(true);
// On resize
$(window).on('resize', function() {
collapseNavTrigger(false);
});
});