POC Priority navigation

In this example below you will see how to do a POC Priority navigation with some HTML / CSS and Javascript

Thumbnail
This awesome code was written by tibomahe, you can see more from this user in the personal repository.
You can find the original code on Codepen.io
Copyright tibomahe ©

Technologies

  • HTML
  • CSS
  • JavaScript
<!DOCTYPE html>
<html lang="en" >

<head>
  <meta charset="UTF-8">
  <title>POC Priority navigation</title>
  
  
  
      <link rel="stylesheet" href="css/style.css">

  
</head>

<body>

  <header class="c-header">
  <div class="l-container">
    <nav class="c-priority-nav js-priority-nav">
      <ul class="c-navbar js-priority-nav__navbar">
        <li>
          <a href="#">Item 1</a>
        </li>
        <li>
          <a href="#">Longer item 2</a>
        </li>
        <li>
          <a href="#">Big bigger big item 3</a>
        </li>
        <li>
          <a href="#">Item 4</a>
        </li>
        <li>
          <a href="#">Not so huge item 5</a>
        </li>
        <li>
          <a href="#">Item 6</a>
        </li>
        <li>
          <a href="#">Yes there is an item 7</a>
        </li>
      </ul>
      <div class="c-priority-nav__overflow js-priority-nav__overflow">
				<a href="#" class="c-priority-nav__trigger js-priority-nav__trigger" title="Liens de navigation masqués">Plus <span class="icon-caret-down"></span></a>
        <ul class="c-priority-nav__hidden-links js-priority-nav__hidden-links u-dropdown-overflow">
        </ul>
      </div>
    </nav>
  </div>
</header>
  <script src='https://cdnjs.cloudflare.com/ajax/libs/jquery/3.1.1/jquery.min.js'></script>

  

    <script  src="js/index.js"></script>




</body>

</html>

/*Downloaded from https://www.codeseek.co/tibomahe/poc-priority-navigation-qmvBKZ */
a {
  font-size: 13px;
  font-family: Helvetica;
  text-decoration: none;
}

.l-container {
  margin-right: auto;
  margin-left: auto;
  max-width: 100%;
  border: 1px solid red;
}
@media (min-width: 576px) {
  .l-container {
    width: 540px;
  }
}
@media (min-width: 768px) {
  .l-container {
    width: 720px;
  }
}
@media (min-width: 992px) {
  .l-container {
    width: 960px;
  }
}
@media (min-width: 1200px) {
  .l-container {
    width: 1140px;
  }
}

.c-header {
  position: relative;
  height: 50px;
  background-color: #333537;
  position: absolute;
  top: 0;
  right: 0;
  left: 0;
  padding: 0 20px;
  font-size: 0;
  z-index: 1001;
}
.c-header .c-priority-nav,
.c-header .c-navbar {
  height: 50px;
  font-size: 13px;
  display: inline-block;
  vertical-align: top;
}
.c-header .c-priority-nav {
  width: 100%;
  text-align: right;
}

.c-priority-nav {
  position: relative;
}
.c-priority-nav__overflow {
  height: 50px;
  position: absolute;
  right: 30px;
  top: 0;
  visibility: hidden;
}
.c-priority-nav__trigger {
  transition: color 0.4s;
  display: block;
  line-height: 50px;
  color: #fff;
}
.c-priority-nav__trigger:focus, .c-priority-nav__trigger:hover {
  color: #CCC;
  text-decoration: none;
  cursor: pointer;
}
.c-priority-nav__hidden-links {
  margin: 0;
  list-style: none;
  display: none;
  position: absolute;
  top: 100%;
  right: -30px;
  padding: 0 20px 15px;
  width: 170px;
  background-color: #333537;
  box-shadow: 0 2px 2px 0 rgba(0, 0, 0, 0.2);
}
.c-priority-nav__hidden-links > li > a {
  transition: color 0.4s;
  display: block;
  line-height: 50px;
  color: #fff;
}
.c-priority-nav__hidden-links > li > a:focus, .c-priority-nav__hidden-links > li > a:hover {
  color: #CCC;
  text-decoration: none;
  cursor: pointer;
}
.c-priority-nav .c-navbar {
  position: absolute;
  top: 0;
  right: 0;
  transition: right 0.4s;
}
.c-priority-nav.is-prioritized .c-priority-nav__overflow {
  visibility: visible;
}
.c-priority-nav.is-prioritized .c-priority-nav__hidden-links.is-open {
  display: block;
}
.c-priority-nav.is-prioritized .c-navbar {
  right: 80px;
}

.c-navbar {
  margin: 0;
  list-style: none;
}
.c-navbar:before, .c-navbar:after {
  content: " ";
  display: table;
}
.c-navbar:after {
  clear: both;
}
.c-navbar > li {
  height: 100%;
  float: left;
  margin-right: 30px;
}
.c-navbar > li + li {
  margin-left: 10px;
}
.c-navbar > li > a:not(.c-btn),
.c-navbar > li > button:not(.c-btn) {
  transition: color 0.4s;
  display: block;
  line-height: 50px;
  color: #fff;
}
.c-navbar > li > a:not(.c-btn):focus, .c-navbar > li > a:not(.c-btn):hover,
.c-navbar > li > button:not(.c-btn):focus,
.c-navbar > li > button:not(.c-btn):hover {
  color: #CCC;
  text-decoration: none;
  cursor: pointer;
}
.c-navbar > li > .c-btn {
  margin-top: 10px;
}


/*Downloaded from https://www.codeseek.co/tibomahe/poc-priority-navigation-qmvBKZ */
// debounce (from underscore.js)
function debounce(func, wait, immediate) {
	var timeout = null;
	return function () {
		var args = arguments,
		    context = this;
		function later() {
			timeout = null;
			if (!immediate) func.apply(context, args);
		}
		var callNow = immediate && !timeout;
		clearTimeout(timeout);
		timeout = setTimeout(later, wait);
		if (callNow) func.apply(context, args);
	};
}

function priorityNav() {

	// Inspired by https://css-tricks.com/the-priority-navigation-pattern/
	// Inspired by https://aws.amazon.com/fr/
	// Inspired by https://github.com/lukejacksonn/GreedyNav

	// Selectors
	// ------------------

	var priorityNavNavbar = '.js-priority-nav__navbar';
	var priorityNavItem = '.js-priority-nav__navbar li';
	var priorityNavOverflow = '.js-priority-nav__overflow';
	var priorityNavHiddenLinks = '.js-priority-nav__hidden-links';
	// Temp
	var priorityNavTrigger = '.js-priority-nav__trigger';

	// Elements
	// ------------------

	var $target = $('.js-priority-nav');
	var $navbar = $target.find(priorityNavNavbar);

	// Init var
	// ------------------

	// array with all the links
	var priorityItem = [];
	var priorityItemLength = 0;
	// array with all the overflown links
	var priorityItemInOverflow = [];
	// array with all the links widths
	var itemWidths = [];
	var priorityNavOverflowWidth = 80;
	// temp
	var closingTime = 1000;
	var timer;

	// Utility functions
	// ------------------

	// show item in navbar and hide in drodpown
	function showItem(index) {
		$(priorityItem).eq(index).show();
		setTimeout(function () {
			$(priorityItemInOverflow).eq(index).hide();
		}, 0);
	}
	// hide item in navbar and show in drodpown
	function hideItem(index) {
		$(priorityItem).eq(index).hide();
		setTimeout(function () {
			$(priorityItemInOverflow).eq(index).show();
		}, 0);
	}
	// Duplicate the links
	function copyAllLinksToDropdown() {
		// empty the dropdown
		$target.find(priorityNavHiddenLinks).empty();
		// set the priorityItem array
		priorityItem = $navbar.find('li');
		priorityItemLength = priorityItem.length;
		// loop for writing all links in dropdown
		for (var i = 0, len = priorityItemLength; i < len; i++) {
			var $priorityItem = $(priorityItem[i]);

			var priorityItemAngularHref = $priorityItem.children().first().attr('ui-sref'),
			    priorityItemHref = $priorityItem.children().first().attr('href'),
			    priorityItemHtml = $priorityItem.children().first().html();

			// if angular --> ui-sref
			if (priorityItemAngularHref) {
				$target.find(priorityNavHiddenLinks).append($('<li><a ui-sref="' + priorityItemAngularHref + '">' + priorityItemHtml + '</a></li>'));
			}
			// if vanilla html --> href
			else if (priorityItemHref) {
					$target.find(priorityNavHiddenLinks).append($('<li><a href="' + priorityItemHref + '">' + priorityItemHtml + '</a></li>'));
				}
		}
		// reassign the array with all the links in dropdown
		priorityItemInOverflow = $target.find(priorityNavHiddenLinks + ' li');
	}
	// Get dimensions
	function getItemsDimensions() {
		itemWidths.length = 0;
		// Set the array
		priorityItem = $target.find(priorityNavItem);
		priorityItemLength = priorityItem.length;
		for (var i = 0, len = priorityItemLength; i < len; i++) {
			var $priorityItem = $(priorityItem[i]);
			// Write the widths
			itemWidths[itemWidths.length] = $priorityItem.outerWidth(true);
		}
	}

	// Main function to update position
	// ------------------

	function updatePositions() {
		// available width (priority nav width - "more" button width)
		var availableWidth = $target.width() - priorityNavOverflowWidth;
		// init the total with
		var totalWidth = 0;
		// boolean to know if overflow has started
		var hasOverflowed = false;
		// boolean to know the index of overflow
		var overflowedAtIndex = -1;

		priorityItemLength = priorityItem.length;

		for (var i = 0, len = priorityItemLength; i < len; i++) {
			totalWidth += itemWidths[i];
			// if available width is not enough
			if (totalWidth > availableWidth) {
				hideItem(i);
				// overflow !
				hasOverflowed = true;
				// which index is overflown ?
				if (overflowedAtIndex === -1) {
					overflowedAtIndex = i;
				}
			}
			// if there is enough space
			else {
					showItem(i);
				}
		}

		/*
  	// Debug
  	console.log('availableWidth : ', availableWidth);
  	console.log('totalWidth : ', totalWidth);
  	console.log('hasOverflowed ? : ', hasOverflowed);
  	console.log('overflowedAtIndex at : ', overflowedAtIndex);
  */

		// Management of the 'more' button
		// 'is-prioritzed' state shows/hides the overflow btn
		// and move the navbar consequently
		if (hasOverflowed) {
			$target.addClass('is-prioritized');
		} else {
			$target.removeClass('is-prioritized');
		}
	}

	// Init function
	// ------------------

	function init() {
		copyAllLinksToDropdown();
		getItemsDimensions();
		updatePositions();
	}

	// TEMP : Manage dropdown
	// ------------------
	// 'is-open' state shows/hides the hidden links
	$target.find(priorityNavTrigger).on('click', function (event) {
		event.preventDefault();
		$target.find(priorityNavHiddenLinks).toggleClass('is-open');
		clearTimeout(timer);
	});

	$target.find(priorityNavHiddenLinks).on('mouseleave', function () {
		timer = setTimeout(function () {
			$target.find(priorityNavHiddenLinks).removeClass('is-open');
		}, closingTime);
	}).on('mouseenter', function () {
		clearTimeout(timer);
	});

	// Call
	// ------------------

	if ($navbar.length) {
		init();
		$(window).on('resize', debounce(updatePositions, 250));
	}
}

// export default priorityNav;
priorityNav();

Comments