Adding an extra button to the list in flexible navigation

I have a navigation that allows me to say 12 elements, and when resolution reduces the number of elements in a new line. I need to do this when the item is no longer suitable for navigation, it should put the β€œMORE” button on the right side of the navigator. and place this item that is not suitable for the dropdown menu. If you do not understand me, there is an image below.

But the problem is that the navigation elements do not always have the same width, since the navigation elements are generated from the REST api.

I tried to make a jQuery script to calculate the width of the elements and add them to the navigation. Here is the script created, I did it in a hurry, so this is really bad.

I need help on how to calculate witdh elements and navigation width correctly and calculate when to add elements to navigation or remove elements from navigation.

Here is the image if you haven’t received it: http://img.hr/aagV

/* * Here we check how many items can we put on the navigation bar * If item doesn't fit we clone it on the more dropdown button */ function removeMany() { var i = $items.length - 1; if (itemsWidth > navWidth) { while (itemsWidth > navWidth) { $($items[i]).removeClass('first-level-item').addClass('second-level-item'); dropdownItems.push($items[i]); $($items[i]).removeClass('showed'); $items.pop(); i--; getItemsWidth(); } $nav.append($navMore); dropdownItems.reverse().forEach(function (element, index, array) { $('ul.second-level').append(element); }); getItems(); } } //If window is resized to bigger resolution we need to put back items on the navbar function addMany() { var i = dropdownItems.length - 1; if (dropdownItems.length != 0) { do { $('ul.first-level').append(dropdownItems.reverse()[i]); $items.push(dropdownItems[i]); dropdownItems.pop(); i--; getItemsWidth(); } while (itemsWidth < navWidth); $navMore.remove(); $items.each(function (i) { $(this).addClass('first-level-item showed').removeClass('second-level-item'); }); if (!(dropdownItems != 0)) { return; } else { $nav.append($navMore); } } } 
 body { margin: 0; padding: 0; border: 0; } ul, li { margin: 0; padding: 0; list-style: none; } ul.second-level li { display: block !important; } ul.second-level li > a { color: black; } a { color: #fff; text-decoration: none; text-transform: uppercase; } .second-level-item a { color: #333 !important; } .navigation { width: 960px; max-width: 100%; background: #211; color: #aaa; margin: 0 auto; } .first-level .first-level-item { display: inline-block; padding: 10px; } .first-level .item-more { display: inline-block; } .first-level .item-more .second-level-item { display: inline-block; } .second-level { position: absolute; top: 100%; right: 0; width: 200px; background: #fff; padding: 10px; box-shadow: 0 4px 10px rgba(0, 0, 0, 0.4); } .has-second-level { position: relative; } .has-second-level .second-level { display: none; } .has-second-level:hover { background: #fff; color: #000; } .has-second-level:hover .second-level { display: block; } /*# sourceMappingURL=style.css.map */ 
 <!doctype html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1"> <title>DropDown</title> <link rel="stylesheet" href="css/reset.css"/> <link rel="stylesheet" href="css/style.css"/> </head> <body> <nav class="navigation"> <ul class="first-level"> <li class="first-level-item showed"><a href="#">Introduction to Irish Culture</a></li> <li class="first-level-item showed"><a href="#">Cellular and Molecular Neurobiology</a></li> <li class="first-level-item showed"><a href="#">Guitar foundations</a></li> <li class="first-level-item showed"><a href="#">Startup Inovation</a></li> <li class="first-level-item showed"><a href="#">Astrophysics</a></li> <li class="first-level-item item-more has-second-level"> <span> More </span> <ul class="second-level"> </ul> </li> </ul> </nav> <script src="https://code.jquery.com/jquery-2.1.1.js"></script> </body> </html> 
+2
source share
3 answers

If you have fixed-width list items, then simply collect additional list items and paste them into a separate list. Here is a simple example. The explanation is in the comments on the code.

View the snippet in full screen and try changing the width of the window.

Also script : http://jsfiddle.net/abhitalks/860LzgLL/

Fullscreen : http://jsfiddle.net/abhitalks/860LzgLL/embedded/result/

Excerpt

 var elemWidth, fitCount, fixedWidth = 120, $menu = $("ul#menu"), $collectedSet; // Assuming that the list-items are of fixed-width. collect(); $(window).resize(collect); function collect() { // Get the container width elemWidth = $menu.width(); // Calculate how many list-items can be accomodated in that width fitCount = Math.floor(elemWidth / fixedWidth) - 1; // Create a new set of list-items more than the fit count $collectedSet = $menu.children(":gt(" + fitCount + ")"); // Empty the collection submenu and add the cloned collection set $("#submenu").empty().append($collectedSet.clone()); } 
 * { box-sizing: border-box; margin: 0; padding: 0; } div { position: relative; background-color: #ccc; height: 32px; overflow: visible; } ul#menu, ol { height: 32px; max-width: 80%; overflow: hidden; } ul#menu > li, ol > li { display: block; float: left; height: 32px; width: 120px; padding: 4px 8px; } ol { position: absolute; right: 0; top: 0; overflow: visible; } ol > li { min-width: 120px; } ol ul { position: absolute; top: 120%; right: 10%; } ol li ul > li { list-style: none; background-color: #eee; border: 1px solid gray; padding: 4px 8px;} 
 <script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script> <div> <ul id="menu"> <li>Option One</li><li>Option Two</li><li>Option Three</li> <li>Option Four</li><li>Option Five</li><li>Option Six</li> </ul> <ol><li>Collected<ul id="submenu"></ul></li></ol> </div> 

Update:

This applies to your request with different / variable width lists. It would be a minor change.

Also script : http://jsfiddle.net/abhitalks/tkbmcupt/1/

Fullscreen : http://jsfiddle.net/abhitalks/tkbmcupt/1/embedded/result/

Excerpt

 var elemWidth, fitCount, varWidth = 0, ctr, $menu = $("ul#menu"), $collectedSet; // Get static values here first ctr = $menu.children().length; // number of children will not change $menu.children().each(function() { varWidth += $(this).outerWidth(); // widths will not change, so just a total }); collect(); // fire first collection on page load $(window).resize(collect); // fire collection on window resize function collect() { elemWidth = $menu.width(); // width of menu // Calculate fitCount on the total width this time fitCount = Math.floor((elemWidth / varWidth) * ctr) - 1; // Reset display and width on all list-items $menu.children().css({"display": "block", "width": "auto"}); // Make a set of collected list-items based on fitCount $collectedSet = $menu.children(":gt(" + fitCount + ")"); // Empty the more menu and add the collected items $("#submenu").empty().append($collectedSet.clone()); // Set display to none and width to 0 on collection, // because they are not visible anyway. $collectedSet.css({"display": "none", "width": "0"}); } 
 * { box-sizing: border-box; margin: 0; padding: 0; } div { position: relative; background-color: #ccc; height: 32px; overflow: visible; } ul#menu, ol { height: 32px; max-width: 80%; overflow: hidden; } ul#menu > li, ol > li { display: block; float: left; height: 32px; white-space: nowrap; padding: 4px 8px; } ol { position: absolute; right: 0; top: 0; overflow: visible; } ol > li { min-width: 120px; } ol ul { position: absolute; top: 120%; right: 10%; } ol li ul > li { list-style: none; background-color: #eee; border: 1px solid gray; padding: 4px 8px;} 
 <script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script> <div> <ul id="menu"> <li>Option One</li><li>Option Two</li><li>Option Three</li> <li>Option Four</li><li>Option Five</li><li>Option Six</li> </ul> <ol><li>Collected<ul id="submenu"></ul></li></ol> </div> 
+3
source

It MUST be optimized (as it is pretty inefficient from what I tested), but it is up to you.

 $(document).ready(function(){ var moreW = $(".more").outerWidth(), //width of your "more" element totalW = -moreW, //cumulated width of list elements totalN = $('.nav li').length - 1, //number of elements minus the "more" element dw = document.documentElement.clientWidth; $('.nav li').each(function(){ totalW += $(this).outerWidth(); }); function moveToDropdown(){ dw = document.documentElement.clientWidth; //moves elements into the list while(totalW > (dw - moreW)){ var temp = $(".nav li:nth-last-child(2)"); //element to be moved totalW = totalW - temp.outerWidth(); $(".dropdown").append(temp.clone()); temp.remove(); } //moves elements out of the list var newList = $('.dropdown li').length; //check if we have elements if(newList > 0){ var element = $('.dropdown li:last-child'), //element to be moved elementW = $('.dropdown li:last-child').outerWidth(); //width of element to be moved if(totalW + elementW < dw - moreW){ while(totalW + elementW < dw - moreW ){ var element = $('.dropdown li:last-child'), elementW = $('.dropdown li:last-child').outerWidth(); totalW = totalW + elementW; $(".nav > li:last-child").before(element.clone()); element.remove(); } } } } moveToDropdown(); $(window).resize(moveToDropdown) }); 
 .clearfix:after{ display:block; content:''; clear:both; } body,html{ width:100%; height:100%; margin:0; padding:0; } ul{ list-style:none; width:100%; padding:0; margin:0; } ul li{ float:left; padding:5px; } .nav > li { position:relative; } .nav ul{ position:absolute; top:25px; } 
 <script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script> <ul class="nav clearfix"> <li><a href="#">Item</a></li> <li><a href="#">Item</a></li> <li><a href="#">Item</a></li> <li><a href="#">Item</a></li> <li><a href="#">Item</a></li> <li><a href="#">Item</a></li> <li><a href="#">Item</a></li> <li class="more"> <a href="#">more</a> <ul class="dropdown"> <!-- we'll add elements here --> </ul> </li> </ul> 
+2
source

The script that Abhitalks made did not work properly for different sizes of elements. I changed the code a bit:

 $(function() { function makeMenuFit() { //Get data var menuSize = menu.width(); //Determine how many items that fit var menuTotalWidth = 0; var itemThatFit = 0; for(var i = 0; i < menuItems.length; i++) { menuTotalWidth += menuItems[i]; if(menuTotalWidth <= menuSize) { itemThatFit++; continue; } break; } menu.children().css({"display": "block", "width": "auto"}); var collectedSet = menu.children(":gt(" + (itemThatFit - 1) + ")"); $("#submenu").empty().append(collectedSet.clone()); collectedSet.css({"display": "none", "width": "0"}); } var menu = $(".tabletNavigation > ul"); var menuItems = []; menu.children().each(function() { menuItems.push($(this).outerWidth()); }); $(window).resize(makeMenuFit); makeMenuFit(); }); 
0
source

Source: https://habr.com/ru/post/1236673/


All Articles