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 when an element with position fixed comes into play. Although we still jump to the desired id, it won't recognise that we have a fixed position element. So it will ignore its height and jump wherever the element with a specific id matches the window top element.

    To solve this, you need to add padding to your scroll jumps, like below:

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

    Learn more about scroll-padding in CSS-Tricks.

    UPDATE

    As we have gone further on this solution, the spying behaviour crashed since the scroll spy will only know whether we are in a section with a specific ID. 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, respecting the height of the fixed navbar. You can read bootstrap scrollspy options for more information about data-offset.