javascriptjqueryresponsive-design

adding more button for list in responsive navigation


I have a navigation of lets say 12 items, and when resolution gets smaller items drop in a new line. I need to make that when an item doesn't fit on a navigation anymore it should put a "MORE" dropdown button on the right side of nav. and put that item that doesn't fit in a dropdown. If you don't understand me there is image below.

But the problem is that navigation items aren't always the same width because navigation items are generated from REST api.

I tryed to make jQuery script for calculating items width and adding them to navigation. Here is the script I created, I made it in a hurry so it's really bad.

I need to help on how to properly calculate items witdh and navigation width and calculating when to add items to navigation or remove items from navigation.

Here is image if you don't get 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>


Solution

  • This question is too old, but i want to post my answer too. Maybe this is more cleaner and easier way. I have created a pen: https://codepen.io/sergi95/pen/bmNoML

    <div id="mainMenu" class="main-menu">
    <ul id="autoNav" class="main-nav">
      <li>
        <a href="#">home</a>
      </li>
      <li>
        <a href="#">about us</a>
      </li>
      <li>
        <a href="#">portfolio</a>
      </li>
      <li>
        <a href="#">team</a>
      </li>
      <li>
        <a href="#">blog</a>
      </li>
      <li>
        <a href="#">contact</a>
      </li>
      <li id="autoNavMore" class="auto-nav-more">
        <a href="#" class="more-btn">more</a>
        <ul id="autoNavMoreList" class="auto-nav-more-list">
          <li>
            <a href="#">policy</a>
          </li>
        </ul>
      </li>
    </ul>
    

    const $mainMenu = $("#mainMenu");
        const $autoNav = $("#autoNav");
        const $autoNavMore = $("#autoNavMore");
        const $autoNavMoreList = $("#autoNavMoreList");
        autoNavMore = () => {
            let childNumber = 2;
    
            if($(window).width() >= 320) {
                // GET MENU AND NAV WIDTH
                const $menuWidth = $mainMenu.width();
                const $autoNavWidth = $autoNav.width();
                if($autoNavWidth > $menuWidth) {
                    // CODE FIRES WHEN WINDOW SIZE GOES DOWN
                    $autoNav.children(`li:nth-last-child(${childNumber})`).prependTo($autoNavMoreList);
                    autoNavMore();
                } else {
                    // CODE FIRES WHEN WINDOW SIZE GOES UP
                    const $autoNavMoreFirst = $autoNavMoreList.children('li:first-child').width();
                    // CHECK IF ITEM HAS ENOUGH SPACE TO PLACE IN MENU
                    if(($autoNavWidth + $autoNavMoreFirst) < $menuWidth) {
                        $autoNavMoreList.children('li:first-child').insertBefore($autoNavMore);
                    }
                }
                if($autoNavMoreList.children().length > 0) {
                    $autoNavMore.show();
                    childNumber = 2;
                } else {
                    $autoNavMore.hide();
                    childNumber = 1;
                }
            }
        }
        // INIT 
        autoNavMore();
        $(window).resize(autoNavMore);
    
    
    .main-menu {
            max-width: 800px;
        }
        .main-nav {
            display: inline-flex;
            padding: 0;
            list-style: none;
        }
        .main-nav li a {
            padding: 10px;
            text-transform: capitalize;
            white-space: nowrap;
            font-size: 30px;
            font-family: sans-serif;
            text-decoration: none;
        }
        .more-btn {
            color: red;
        }
        .auto-nav-more {
            position: relative;
        }
        .auto-nav-more-list {
            position: absolute;
            right: 0;
            opacity: 0;
            visibility: hidden;
            transition: 0.2s;
            text-align: right;
            padding: 0;
            list-style: none;
            background: grey;
            border-radius: 4px;
        }
        .auto-nav-more:hover .auto-nav-more-list {
            opacity: 1;
            visibility: visible;
        }