Search code examples
htmlcsstwitter-bootstrapbootstrap-4scrollspy

Bootstrap Scroll Spy with Sticky Navbar not working as expected


I'm having a problem with Bootstrap Scrollspy component.

I'm using a sticky-top navbar and when the nav button is clicked it scrolls to the correct element;

But the problem is that the sticky navbar is overlaying this element.

I tried using data-offset = "50" in the body tag but it affected nothing.

The body tag:

<body data-spy="scroll" data-target="#sectionsNav" data-offset="50">

The body tag css:

body {
  position: relative;
  overflow-y: auto;
}

The navbar:

<nav class="navbar navbar-light bg-light sticky-top">
        <div id="sectionsNav">
            <ul class="nav nav-pills text-center">
                <li class="nav-item">
                    <a class="nav-link" href="#wihe">What is Home Eats</a>
                </li>
                <li class="nav-item">
                    <a class="nav-link" href="#hiw">How it Works</a>
                </li>
                <li class="nav-item">
                    <a class="nav-link" href="#pws">Problems we Solve</a>
                </li>
                <li class="nav-item">
                    <a class="nav-link" href="#jhen">Join Now!</a>
                </li>
            </ul>
        </div>
    </nav>

How it works div:

..
<div id="hiw" class="container">
...
..
.
</div>
..

Expected Behavior on clicking How it works button in the nav:

Expected Behaviour image

Occurring Behaviour:

Occurring Behaviour image Note That: The navbar is above How it Works header.

Edit

After applying @SMAKSS answer the scroll worked as charm. But another problem occured, in the navbar the highlighted element becomes the previous element.

At the following screenshot I pressed on How it Works and it scrolled correctly, But the highlighted navbar element is What is home eats which is the previous one. Incorrect highlighting i.e. If I clicked on Problems we Solve, How it Works becomes selected. It always select the previous one.

Edit Solution

I fixed the second problem by doubling the data-offset attribute to be 100. the code now looks like this:

<head>
 <style>
    html {
    scroll-padding-top: 70px;
    }

    body {
    position: relative;
    overflow-y: auto;
    }
 </style>
</head>

<body data-spy="scroll" data-target="#sectionsNav" data-offset="100">
...
.
</body>


Solution

  • The problem here happens because of when an element with position fixed came into the play browser will still jump to the desired id but won't determine the element with position fix is still there so it will ignore its height and will jump where ever the element with specific id match the window top element.

    So you should let browser now in each scroll you need padding on jumping like this:

    html {
      scroll-padding-top: 70px; /* height of sticky header */
    }
    

    This is the full article that might help more.

    UPDATE

    As we have gone further on this solution since the scroll spy will only know whether we are in a section with specific id or not the spying behavior crashed. So to fix this there are several approaches like adding padding to each section according to navbar height or as @Raamyy suggested approach, we can define data-offset on our body tag, again with the height of the fixed navbar. For more information about data-offset you can read this.