17

I have a Bootstrap 4 layout similar to this: https://www.codeply.com/go/yLO99L66MD

When there are too many nav items, I want them to be hidden, so I added this: nav {overflow:hidden}. This does the job, but the problem is that it also hides my dropdown menu. How can I hide extra menu items but still allow dropdowns to show up for visible items?

<nav class="navbar navbar-expand-md navbar-dark bg-dark">
    <a class="navbar-brand" href="#">Navbar</a>
    <button class="navbar-toggler" type="button" data-toggle="collapse" data-target="#navbarsExampleDefault" aria-controls="navbarsExampleDefault" aria-expanded="false" aria-label="Toggle navigation">
        <span class="navbar-toggler-icon"></span>
    </button>

    <div class="collapse navbar-collapse" id="navbarsExampleDefault">
        <ul class="navbar-nav mr-auto">
            <li class="nav-item active">
                <a class="nav-link" href="#">Home <span class="sr-only">(current)</span></a>
            </li>
            <li class="nav-item">
                <a class="nav-link" href="#">Link</a>
            </li>
            <li class="nav-item">
                <a class="nav-link disabled" href="#">Disabled</a>
            </li>
            <li class="nav-item dropdown">
                <a class="nav-link dropdown-toggle" href="http://example.com" id="dropdown01" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">Dropdown</a>
                <div class="dropdown-menu" aria-labelledby="dropdown01">
                    <a class="dropdown-item" href="#">Action</a>
                    <a class="dropdown-item" href="#">Another action</a>
                    <a class="dropdown-item" href="#">Something else here</a>
                </div>
            </li>

            <li class="nav-item">
                <a class="nav-link" href="#">aaaaaaaa aaaaa </a>
            </li>

            <li class="nav-item">
                <a class="nav-link" href="#">bbbbbb bbbbb</a>
            </li>

            <li class="nav-item">
                <a class="nav-link" href="#">cccccccc cccccccc </a>
            </li>

            <li class="nav-item">
                <a class="nav-link" href="#">dddd ddddddddd </a>
            </li>
            <li class="nav-item">
                <a class="nav-link" href="#">eeeeeeeeeeeeeeeeee cv kbc vxckjvhkxcv </a>
            </li>


        </ul>

    </div>
</nav>

<div class="container">

    <div class="starter-template">
        <h1>Bootstrap starter template</h1>
        <p class="lead">Use this document as a way to quickly start any new project.
            <br> All you get is this text and a mostly barebones HTML document.</p>
    </div>

</div>
<!-- /.container -->
janeh
  • 3,734
  • 7
  • 26
  • 43

7 Answers7

14

You can use the navbar as this given example.

When you resize the browser the nav items will be moved inside to the drop-down if it not have an enough space.

Demo

[1]: http://jsfiddle.net/swasatz/3fn4d5oq/

Snippet Demo

Open the snippet in full page mode and resize the browser to see the changes.

$(document).ready(function () {
    var menu = $("#nav-bar-filter"),
        subMenu = $(".subfilter"),
        more = $("#more-nav"),
        parent = $(".filter-wrapper"),
        ww = $(window).width(),
        smw = more.outerWidth();

    menu.children("li").each(function () {
        var w = $(this).outerWidth();
        if (w > smw) smw = w + 20;
        return smw
    });
    more.css('width', smw);

    function contract() {
        var w = 0,
            outerWidth = parent.width() - smw - 50;
        for (i = 0; i < menu.children("li").size(); i++) {
            w += menu.children("li").eq(i).outerWidth();
            if (w > outerWidth) {
                menu.children("li").eq(i - 1).nextAll()
                    .detach()
                    .css('opacity', 0)
                    .prependTo(".subfilter")
                    .stop().animate({
                    'opacity': 1
                }, 300);
                break;
            }
        }
    }

    function expand() {
        var w = 0,
            outerWidth = parent.width() - smw - 20;
        menu.children("li").each(function () {
            w += $(this).outerWidth();
            return w;
        });
        for (i = 0; i < subMenu.children("li").size(); i++) {
            w += subMenu.children("li").eq(i).outerWidth();
            if (w > outerWidth) {
                var a = 0;
                while (a < i) {
                    subMenu.children("li").eq(a)
                        .css('opacity', 0)
                        .detach()
                        .appendTo("#nav-bar-filter")
                        .stop().animate({
                        'opacity': 1
                    }, 300);
                    a++;
                }
                break;
            }
        }
    }
    contract();

    $(window).on("resize", function (e) {
        ($(window).width() > ww) ? expand() : contract();
        ww = $(window).width();
    });

});
body {
    font-family: verdana;
    min-width: 250px;
}
ul#more-nav, ul#nav-bar-filter {
    display: inline-block;
    vertical-align: top;
}
ul {
    list-style-type: none;
    padding: 0;
    margin: 0;
}
li {
    padding: 4px 8px 4px 8px;
    margin: 0;
}
#nav-bar-filter li {
    display: inline-block;
    font-weight: bold;
}
a {
    text-decoration: none;
    color: #666;
    font-size: 13px;
}
.filter-wrapper {
    width: 100%;
    background: #eee;
    padding: 5px 10px 5px 10px;
}
#more-nav {
    float: right;
}
.subfilter{
    padding-top: 10px;
}
.subfilter li {
    margin: 0 0 0 20px;
    padding: 5px 0 0 0;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="twelve columns filter-wrapper">
    <ul class="nav-bar-filter" id="nav-bar-filter">
        <li><a href="#">All</a> 
        </li>
        <li><a href="#">Small</a>

        </li>
        <li><a href="#">Medium</a>

        </li>
        <li><a href="#">Extra large</a>

        </li>
        <li><a href="#">Text</a>

        </li>
        <li><a href="#">Small-1</a>

        </li>
        <li><a href="#">Medium-1</a>

        </li>
        <li><a href="#">Extra large text</a>

        </li>
        <li><a href="#">Large text</a>

        </li>
        <li><a href="#">Another text</a>

        </li>
        <li><a href="#">text</a>

        </li>
    </ul>
    <ul id="more-nav">
        <li><b><a href="#">More &gt;</a></b>

            <ul class="subfilter"></ul>
        </li>
    </ul>
</div>
Satheesh Kumar
  • 2,205
  • 1
  • 16
  • 31
  • I faced the similar problem and there is no need to use any extra JS or other tricks, please take a look at my answer https://stackoverflow.com/questions/46477802/bootstrap-4-nav-hiding-extra-menu-items/48176491#48176491 – horbor Jan 09 '18 at 20:57
  • @horbor, Here the issue is not showing/hiding the nav items with appropriate to screen size. The actual scenario is the user has a number of nav items which doesn't have enough space to show. For that, I have come up with the solution to move the extra nav items into dropdown by using jquery. Hope you got a clear idea now. Thanks :) – Satheesh Kumar Jan 10 '18 at 12:04
2

For the menu-items that you would like to view as hidden on mobile devices, wrap a span around the list-item(s) that you want hidden and add the bootstrap 4 beta hidden values, like this.

<span class="d-none d-xs-block">
  <li class="nav-item">
    <a class="nav-link" href="#">aaaaaaaa 1234 </a>
  </li>
</span>

You can also apply the class to an <a> tag to hide that specific link within the drop-down menu. Furthermore, tinker with the d-xs-block class to meet your specifications.

I would like to provide you with a couple of sources to help guide you with regards to hiding elements at specific breakpoints.

nicolallias
  • 1,055
  • 2
  • 22
  • 51
Mister Moody
  • 114
  • 1
  • 10
1

Here is a natural Bootstrap 4 solution, with no JS or extra CSS required. Instead of using ul you can use div according to documentation and use display property to show or hide certain elements in navbar, including dropdown depending on screen size.

Here is what documentation says:

because we use classes for our navs, you can avoid the list-based approach entirely if you like. nav documentation

Here is an example, I added dropdown as div too:

<div class="navbar-nav ml-auto">
    <a class="nav-item nav-link" href="#">How does it work</a>
    <a class="nav-item nav-link" href="#">Demo</a>
    <div class="nav-item dropdown" href="#">
        <a class="nav-link dropdown-toggle" href="#" id="dropdown01" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">Dropdown</a>
        <div class="dropdown-menu" aria-labelledby="dropdown01">
            <a class="dropdown-item" href="#">Action</a>
            <a class="dropdown-item" href="#">Another action</a>
            <a class="dropdown-item" href="#">Something else here</a>
        </div>
    </div>
    <a class="nav-item nav-link d-block d-lg-none d-xl-none" href="#">Show only on md and down</a>
    <a class="nav-item nav-link d-none d-lg-block d-md-block" href="#">Show on md and lg</a>
</div>

It's a working native solution. You can show / hide any element of nav this way on any screen size and it will show up in mobile menu too when collapsed.

P.S. no need in overflow:hidden too

Good luck!

horbor
  • 609
  • 7
  • 13
1

Here is another option for Bootstrap 4 that will collapse the extra Navbar items into a dropdown menu on the right side. Use some logic (this is using jQuery) to control the placement of items in the menu...

function (menu,maxHeight) {

    var nav = $(menu);

    // check height of menu
    var navHeight = nav.innerHeight();

    // when the height is taller the navbar has wrapped onto 2 lines
    if (navHeight >= maxHeight) {
        $(menu + ' .dropdown').removeClass('d-none');
        $(".navbar-nav").removeClass('w-auto').addClass("w-100");
        while (navHeight > maxHeight) {
            //  add child to dropdown
            var children = nav.children(menu + ' li:not(:last-child)');
            var count = children.length;
            $(children[count - 1]).prependTo(menu + ' .dropdown-menu');
            navHeight = nav.innerHeight();
        }
        $(".navbar-nav").addClass("w-auto").removeClass('w-100');
    }
    else {
        var collapsed = $(menu + ' .dropdown-menu').children(menu + ' li');

        if (collapsed.length===0) {
          $(menu + ' .dropdown').addClass('d-none');
        }

        while (navHeight < maxHeight && (nav.children(menu + ' li').length > 0) && collapsed.length > 0) {
            //  remove child from dropdown
            collapsed = $(menu + ' .dropdown-menu').children('li');
            $(collapsed[0]).insertBefore(nav.children(menu + ' li:last-child'));
            navHeight = nav.innerHeight();
        }

        if (navHeight > maxHeight) { 
            autocollapse(menu,maxHeight);
        }
    }
}

https://www.codeply.com/go/IETSah3bFG

Carol Skelly
  • 351,302
  • 90
  • 710
  • 624
0

(UPDATED ANSWER) You can use jQuery to show nav menus that fit within window and hide the rest:

jQuery:

$(window).resize(function() {
    var winwidth=$(window).width(),totwidth=$('.navbar .navbar-brand').outerWidth(),shownnum=0;
    var navs=$('.navbar .nav-item');
    navs.each(function(i) {
        totwidth+=$(this).outerWidth();
        if(totwidth<winwidth) shownnum=i+1; else return false;
    });
    navs.show().slice(shownnum).hide();
});

CSS:

.navbar {overflow:hidden}
.nav-item {white-space:nowrap}

Fiddle: https://www.bootply.com/59hJN5jFZo

Taufik Nur Rahmanda
  • 1,862
  • 2
  • 20
  • 36
  • That would not be ideal, I can't count on 4 items fitting in the menu - what if somebody creates 2 or 3 items with very very long names? The 3rd one would stick outside of menu bounds. That's the tricky part is that menus are dynamically generated from user settings. – janeh Oct 04 '17 at 13:54
  • @janehouse I've updated my answer with corrected fiddle too, please check :-) – Taufik Nur Rahmanda Oct 05 '17 at 02:59
0

The following fragment implements a "mega menu" (similar to Yamm3 Megamenu for Bootstrap 3, cf. http://geedmo.github.io/yamm3/) based on Bootstrap 4's flexbox classes:

<!-- adapted from bs-repo basic navbar example code -->
<nav id="navbar" class="navbar navbar-expand-lg navbar-light bg-light">
  <a class="navbar-brand" href="#">Navbar</a>
  <button class="navbar-toggler" type="button"
          data-toggle="collapse" data-target="#navbarSupportedContent">
    <span class="navbar-toggler-icon"></span>
  </button>
  <div class="collapse navbar-collapse" id="navbarSupportedContent">
    <ul class="navbar-nav mr-auto">
      <li class="nav-item active">
        <a class="nav-link" href="#">Home <span class="sr-only">(current)</span></a>
      </li>
      <li class="nav-item">
        <a class="nav-link" href="#">Other</a>
      </li>
      <li class="nav-item dropdown">
        <a class="nav-link dropdown-toggle" href="..."
           id="navbarDropdownMenuLink" data-toggle="dropdown">
          Dropdown link
        </a>
        <div class="dropdown-menu">
          <ul class="d-md-inline-flex flex-md-row">
            <li class="dropdown-item">
              <ul class="d-md-inline-flex flex-md-column">
                <li class="dropdown-item"><a href="#">Action</a></li>
                <li class="dropdown-item"><a href="#">Another</a></li>
                <li class="dropdown-item"><a href="#">Another</a></li>
              </ul>
            </li>
            <li class="dropdown-item">
              <ul class="d-md-inline-flex flex-md-column">
                <li class="dropdown-item"><a href="#">Action</a></li>
                <li class="dropdown-item"><a href="#">Another</a></li>
                <li class="dropdown-item"><a href="#">Another</a></li>
              </ul>
            </li>
            <li class="dropdown-item">
              <ul class="d-md-inline-flex flex-md-column">
                <li class="dropdown-item"><a href="#">Action</a></li>
                <li class="dropdown-item"><a href="#">Another</a></li>
                <li class="dropdown-item"><a href="#">Another</a></li>
              </ul>
            </li>
          </ul>
        </div>
      </li>
    </ul>
    <form class="form-inline my-2 my-lg-0">
      <input class="form-control mr-sm-2" type="text"
             placeholder="Search">
      <button class="btn btn-outline-success my-2 my-sm-0"
              type="submit">Search</button>
    </form>
  </div>
</nav>

Compared to Bootstrap's basic navbar example, there's another div here for the dropdown-menu containing the ul making up the menu since display: flex doesn't go with display: none as dynamically set by Bootstrap's dropdown support script (popper.js).

This variant applies flex row layout on md resolutions and up, while applying plain unordered-list formatting on resolutions below-md.

imhotap
  • 2,275
  • 1
  • 8
  • 16
-1

increase width of div or break menu after hiding menu.

Demo Demo
  • 82
  • 5