Sticky navbar on scroll

I have a header with two rows (top-bar and navbar) I would like the navbar to become sticky as soon as it reaches the top. I could use something like:

<nav class="navbar navbar-light navbar-expand-lg" data-spy="affix" data-offset-top="40">

But that would mean that I need to give the top-bar div a fixed height of 40px while I prefer to work without fixed heights. Does anyone know a way to accomplish what I want without using fixed heights?

Thank you in advance

Use position:sticky and you won’t need JS or need a fixed height.

You do need the correct structure to achieve this but I’d need to see your working page to give specific details.

Hi Paul. Thank you for the response. top-bar and nave are tow separate rows. I mean they are not wrapped in another container:

<div class="top-bar">
	<div class="container">
    	<div class="row">
        	<div class="col-md-6 col-sm-12">

            </div>
        </div>
    </div>
</div>

<nav class="navbar navbar-light navbar-expand-lg position-sticky">
       <div class="container">
    	<div class="navbar-header">
        
                 </div>
        <div class="collapse navbar-collapse" id="navbarNavDropdown">
        	<ul class="navbar-nav ml-auto">
            
                  </ul>
        </div>
    </div>
</nav>

Would this do the trick?

Thank you @TechnoBear for the edit :slight_smile:

1 Like

position:sticky is based on the parent container so assuming your parent container of the navbar is the body or a whole page container then you would just do this.

.position-sticky{
position:-webkit-sticky;/* needed for ios*/
position:sticky;
top:0;
}

Hi Paul. Thanx a lot for the reply. It is working great as usual. I have one last question if you don’t mind.

The initial background of the navbar is transparent. I would like that to change to black when the navbar reaches the top. Can that be done without JS?

Thank you in advace

My first thoughts were no that you’d have to use JS to add a class when the element meets the top.

However with a bit of lateral thinking we may be able to get close by using a fixed background attachment which only shows a linear gradient of solid colour for 100px (the height of the sticky element). It’s a bit magic numberish but may suffice.

Proof of concept here:

https://codepen.io/paulobrien/pen/XWJrjJx

It won’t work on mobile as iOS doesn’t like the background-attachment:fixed so maybe supply a solid color for smaller screens in a media query.

1 Like

Hi Paul. Nice one indeed. For this one I really don’t want to work with height or min-height. For my next site I will work this one out So I presume i have to work with JS anyway. Now I only need to find an example. Do you maybe know of a js tutorial or example achieving what I need?

Position sticky is great in that it caters for fluid height automatically so you don’t need JS.

You only need JS if you want to create some dynamic behavior once the element is sticky.

You wanted to change background colors so apart from the trick I showed above you would need to add a class with JS to effect that’s change when the element becomes sticky.

I gave you a link in my previous post to an example that shows the best way to do this :slight_smile:

EDIT:

This demo may be easier for you to use.

Note that position:sticky doesn’t work in IE11 but no harm done as it will just scroll as normal (Intersection observer doesn’t work in IE11 either so shouldn’t be a problem).

I’ve created a codepen using the above js which may be simpler to see.

https://codepen.io/paulobrien/pen/povzpga

Very very very nice one Paul. I am gonna play with it some time and keep you informed. Thanks a lot

1 Like

That codepen will work on ios also.

You don’t actually need any heights or min-height and will work based on content.

IE11 will just get a normal scroll away header.

Just for fun a non js version that will work on IOS.

http://www.pmob.co.uk/temp2/position-sticky-background2.html

It relies on magic numbers (fixed heights) to work so is not something you should really use unless you had no choice.:slight_smile:

1 Like

Hi Paul thanks again for the reply.

I hope you don’t blame me for my ignorance. but I really don’t understand any of the last two examples. So I think I’ll just limit myself to position sticky:

.navbar{
	position:-webkit-sticky;
	position:sticky;
	top:0;
}

as you suggested in post #5. Now I only need the color change when it reaches the top. I don’t know what’s wrong with me today but I can’t get it done while I think it’s very simple.

I gave you a working example here.

https://codepen.io/paulobrien/pen/povzpga

If you use the same classnames and html structure in your example then it should work ok.

If you can’t get it working then you will need to post your demo or at least the full html and css/js.

If you don’t understand how it is working then tell me what bits you are confused with and I will run through the workings.

The basics of the js method is that a dynamically created 1px x 1px div is inserted above the sticky element and the js (Intersection observer) watches until that element disappears above the viewport. Once it has disappeared we can assume that the sticky element must be sticky so it adds a class called sticky-element to the sticky element so that you can change the colour and anything else that you want.

You don’t really need to know much more than that as long as your JS is addressing the correctly named elements. You can of course change all the class names to suit but you must do that in the js and the css.

Let me know which parts you don;t understand or what is troubling you. Otherwise post your full code and I will adapt to your exact code.

1 Like