Skip to content

Instantly share code, notes, and snippets.

@perifer
Created November 21, 2011 20:30
Show Gist options
  • Save perifer/1383829 to your computer and use it in GitHub Desktop.
Save perifer/1383829 to your computer and use it in GitHub Desktop.
Responsive menu
(function($){
$.fn.adaptiveMenu = function(options) {
// Create some defaults, extending them with any options that were provided
var settings = $.extend({
resize: true,
resizeDelay: 20
}, options),
resizeTimer = false,
els = this;
if (settings.resize) {
$(window).resize(function() {
if (resizeTimer !== false) {
clearTimeout(resizeTimer);
}
resizeTimer = setTimeout(function() {resize(els);}, settings.resizeDelay);
});
};
return els.each(function() {
var aM = {};
aM.$el = $(this);
aM.$list = $("ul", aM.$el);
aM.$menuItems = $('li', aM.$list);
aM.menuItemCount = aM.$menuItems.length;
aM.lastMenuItem = aM.menuItemCount - 1;
aM.menuWidth = aM.$list.width();
aM.lastRemovedWidth = 0;
aM.$dropdown = $('<ul class="am-dropdown"></ul>').append(aM.$list.html()).insertAfter(aM.$el);
aM.$dropdownItems = $('li', aM.$dropdown);
aM.$more = $('<li class="am-more"><a href="#">More…</a></li>').appendTo(aM.$list).hide();
aM.moreWidth = aM.$more.width();
// Store data on the element, used by the resize event.
aM.$el.data('adaptiveMenu', aM);
aM.$more.click(function(){
aM.$dropdown[aM.dropdownVisible ? 'hide' : 'show']();
aM.dropdownVisible = !aM.dropdownVisible;
return false;
});
checkMenu(aM);
});
};
/** Helper functions **/
function checkMenu(aM) {
if (doRemove(aM)) {
aM.$more.show();
while(doRemove(aM)) {
updateItems(aM);
};
}
else if (doAdd(aM)) {
// Add items
while(doAdd(aM)) {
updateItems(aM, true);
if (aM.lastMenuItem + 1 === aM.menuItemCount) {
aM.$more.hide();
aM.menuWidth = aM.$list.width();
}
}
};
}
function doRemove(aM) {
return aM.lastMenuItem > -1 && aM.$el.width() < aM.menuWidth;
}
function doAdd(aM) {
return aM.lastMenuItem < aM.menuItemCount - 1 &&
// Subtract the .more element with when showing the last element.
aM.$el.width() > aM.menuWidth + aM.lastRemovedWidth - ((aM.lastMenuItem === aM.menuItemCount - 2) ? aM.moreWidth : 0);
}
function updateItems(aM, add) {
var n = (add ? 1 : 0),
itemN = aM.lastMenuItem + n;
$item = $(aM.$menuItems[itemN]);
$(aM.$dropdownItems[itemN]).css('display', (add ? 'none' : 'block'));
aM.lastRemovedWidth = $(aM.$menuItems[itemN + n]).width();
$item[add ? 'removeClass' : 'addClass']('hide');
aM.menuWidth = aM.$list.width();
aM.lastMenuItem = itemN - 1 + n;
};
function resize(els) {
els.each(function() {
var aM = $(this).data('adaptiveMenu');
if (aM.dropdownVisible) {
aM.$dropdown.hide();
aM.dropdownVisible = false;
}
checkMenu(aM);
});
};
})(jQuery);
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
"http://www.w3.org/TR/html4/loose.dtd">
<html class="no-js" lang="en">
<script src="http://code.jquery.com/jquery.js" type="text/javascript" charset="utf-8"></script>
<script type="text/javascript" charset="utf-8">
// Remove "no-js" class from <html> element, if it exists, and add "js" class.
document.documentElement.className = document.documentElement.className.replace(/\bno-js\b/, '') + ' js';
</script>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<style type="text/css" media="screen">
body, ul, li {
margin: 0;
padding: 0;
}
.header {
position: relative;
}
.menu {
width: 100%;
background: red;
overflow: hidden;
}
.menu ul {
float: left;
white-space: nowrap;
line-height:1;
font-size: 0; /* prevent whitespace issue when using inline-block */
}
.menu ul li {
list-style: none;
margin-left: 1px;
font-size: 16px; /* override font-size: 0 */
display: inline-block;
/* IE7 inline block fix */
zoom: 1;
*display: inline;
}
.menu li.hide {
display: none;
}
.dropdown {
position: absolute;
display: none;
width: 100%;
}
.dropdown li {
display: none
}
/* Theme */
.header {
margin: 50px;
}
.menu {
background: silver;
min-width: 52px;
}
.menu ul li a {
padding: 0.25em 20px;
background: #000;
color: #fff;
display: block;
}
.dropdown {
background: red;
}
</style>
</head>
<body>
</body>
<div class="header">
<div class="menu">
<ul>
<li><a href="#">1 Home</a></li><li><a href="#">2 News</a></li>
<li><a href="#">3 Client & Cases</a></li>
<li><a href="#">4 Our Process</a></li>
<li><a href="#">5 We are Wonderleap</a></li>
<li><a href="#">6 About Us</a></li><li><a href="#">7 Contact</a></li>
</ul>
</div>
</div>
<p><a href="#">LINK</a></p>
<p>Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.</p>
<script type="text/javascript" charset="utf-8">
var $el = $(".menu"),
$list = $("ul", $el),
$menuItems = $('li', $list),
menuItemCount = $menuItems.length,
lastMenuItem = menuItemCount - 1,
menuWidth = $list.width(),
lastRemovedWidth = 0,
$dropdown = $('<ul class="dropdown"></ul>').append($list.html()).insertAfter($el),
$dropdownItems = $('li', $dropdown),
$more = $('<li class="more"><a href="#"> V </a></li>').appendTo($list).hide(),
moreWidth = $more.width(),
resizeTimer = false,
dropdownVisible = false;
function updateItems(add) {
var n = (add ? 1 : 0),
itemN = lastMenuItem + n;
$item = $($menuItems[itemN]);
$($dropdownItems[itemN]).css('display', (add ? 'none' : 'block'));
lastRemovedWidth = $($menuItems[itemN + n]).width();
$item[add ? 'removeClass' : 'addClass']('hide');
menuWidth = $list.width();
lastMenuItem = itemN - 1 + n;
};
function doRemove() {
return lastMenuItem > -1 && $el.width() < menuWidth;
}
function doAdd() {
return lastMenuItem < menuItemCount - 1 &&
$el.width() > menuWidth + lastRemovedWidth - ((lastMenuItem === menuItemCount - 2) ? moreWidth : 0);
}
function checkMenu() {
if (doRemove()) {
$more.show();
while(doRemove()) {
updateItems();
};
}
else if (doAdd()) {
// Add items
while(doAdd()) {
updateItems(true);
if (lastMenuItem + 1 === menuItemCount) {
$more.hide();
menuWidth = $list.width();
}
}
};
}
$more.click(function(){
$dropdown[dropdownVisible ? 'hide' : 'show']();
dropdownVisible = !dropdownVisible;
});
$(window).resize(function() {
if (dropdownVisible) {
$dropdown.hide();
dropdownVisible = false;
}
if (resizeTimer !== false) {
clearTimeout(resizeTimer);
}
resizeTimer = setTimeout(checkMenu, 20);
});
checkMenu();
//$(elm).adaptiveMenu({'resize':false, 'dropdownEvent':'hover'});
</script>
</html>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment