Bootstrap 4 Floating Sticky Nav over Hero image

I built a hero section with a floating nav where the nav bar is sticky after scrolling. Everything is looking like I want, but this markup is going to be difficult to work with when I separate the parts to put them into wordpress template files. I’m looking for help cleaning this up a bit.

How do I recreate this where all the nav html comes first and then the hero section comes after the closing header tag. Is there a cleaner way than trying to use absolute positioning and negative margins?

Maybe it’s too early in the morning and I’m over thing this?

Here is a codepen

The main problem is that you seem to want your hero background image to be behind your social and nav elements. If this is a ‘must have’ then you would have no option but to offset the hero and drag it back under the nav if you moved the html to separate blocks.

There are also 2 other things to consider in that firstly your fixed header will disappear once the header div has scrolled away as position:sticky is sticky in regards to its container and not the viewport. This happens in your example once you scroll the header away and then the nav scrolls away once the header hero has scrolled. If you move the html so that the hero is no longer in the header image then the nav will not remain sticky because the header is only the size of the nav and is therefore already at the boundary of its container and will scroll away.

You would need to move the nav out of the header div and be a direct child of the body and then it will stick at the top while all the page content scrolls.

I would be inclined to remove the social and nav from the header div and have the hero start underneath the nav and not behind it. This means you won’t cut off any of the image when first displayed.

Here’s how I would go about it (note I added a background colour behind the social icons because the hero image no longer lies behind it).

I basically just moved those elements out of the header altogether.

If you want the hero behind those elements then you will have to use a magic number fix and put a negative top margin on the hero and adjust z-indexes accordingly.

thanks again Paul!

follow up question :slight_smile: … How can I target the navbar elements after the navbar is fixed? I thought I remembered it adding a fixed class or something after it affixes but I don’t see anything added to target just the “Fixed” elements (after sticky is fixed).

For example, if I want to change the background opacity of this element

I believe that the bootstrap ‘affix’ class method was dropped in bootstrap4 in favour of just using the normal css of position:sticky. That means that there is no trigger for you to change the nav once it becomes stuck.

You would need to write a script that detects when an element is sticky and then apply a class to it so that you can style it accordingly. As it happens I have a demo of this that was asked for by someone in the forums so you should be able to deconstruct it and use the useful bits.

It should be pretty self explanatory so just fork and play around with the codepen until you understand how it works :slight_smile:

1 Like

In case you are stuck I have added it to my codepen of your code.:slight_smile:

I’m pretty close… with your help everything is working as expected now except one thing… one smaller screens when you click the hamburger icon to expand the nav it’s pushing the background image (or what ever in in screen depending on scroll) down leaving a white space.

any ideas on that?

On smaller screens you probably want the nav to be position:absolute so that it overlays content rather than pushing it down and that will solve the issue you are having at the same time.


 @media screen and (max-width: 991.98px) {

  .sticky-top .navbar-collapse {
    position: absolute;
    left: 0;
    right: 0;
    top: 100%;
    background: rgba(118, 156, 191, 1);

I’ve added it into my codepen as an example but you may still need to adjust the styling to suit on smaller screen. Add any tweaks in the media query as required.

Another idea would be simply to hide the social icons on smaller screens so that the nav is always at the top and always sticky. (You could add another set of social icons into the dropdown menu which only gets shown at small screen although I’m not keen on duplicating content but could be an easy solution here)

I see you hi-jacked the scroll event to add your dynamic class and although that method works it tends to make the browser work harder than it needs to because it is checking that routine every time the page is scrolled and basically for every pixel. If the page is ‘heavy’ you could find that scrolling becomes ‘janky’ (a technical term) and not a pleasant experience. Modern browsers are better at this but if I use the scroll event I would want to use a debounce routine so that it doesn’t run on every pixel.

The method I provided in my example is so much smoother and needs no ‘magic numbers’ or reference to the scroll event and will not add any lag to normal window scrolling.