How Does the "Position: Sticky;" Property Work?
I Want to Make the Navigation Bar Stick to the Top of the Viewport Once a User Scrolls the Page, but It's Not Working and I Have No Clue Why. If You Can Please...
I want to make the navigation bar stick to the top of the viewport once a user scrolls the page, but it's not working and I have no clue why. If you can please help, here is my HTML and CSS code:
.container {
min-height: 300vh;
}
.nav-selections {
text-transform: uppercase;
letter-spacing: 5px;
font: 18px "lato",sans-serif;
display: inline-block;
text-decoration: none;
color: white;
padding: 18px;
float: right;
margin-left: 50px;
transition: 1.5s;
}
.nav-selections:hover{
transition: 1.5s;
color: black;
}
ul {
background-color: #B79b58;
overflow: auto;
}
li {
list-style-type: none;
}
<main class="container">
<nav style="position: sticky; position: -webkit-sticky;">
<ul align="left">
<li><a href="#/contact" class="nav-selections" style="margin-right:35px;">Contact</a></li>
<li><a href="#/about" class="nav-selections">About</a></li>
<li><a href="#/products" class="nav-selections">Products</a></li>
<li><a href="#" class="nav-selections">Home</a></li>
</ul>
</nav>
</main>
32 Answers
Check if an ancestor element has overflow set (e.g. overflow:hidden); try toggling it. You may have to inspect the DOM tree higher than you expect =).
This may affect your position:sticky on a descendant element.
Sticky positioning is a hybrid of relative and fixed positioning. The element is treated as relative positioned until it crosses a specified threshold, at which point it is treated as fixed positioned.
...
You must specify a threshold with at least one oftop,right,bottom, orleftfor sticky positioning to behave as expected. Otherwise, it will be indistinguishable from relative positioning. [source: MDN]
So in your example, you have to define the position where it should stick in the end by using the top property.
html, body {
height: 200%;
}
nav {
position: sticky;
position: -webkit-sticky;
top: 0; /* required */
}
.nav-selections {
text-transform: uppercase;
letter-spacing: 5px;
font: 18px "lato", sans-serif;
display: inline-block;
text-decoration: none;
color: white;
padding: 18px;
float: right;
margin-left: 50px;
transition: 1.5s;
}
.nav-selections:hover {
transition: 1.5s;
color: black;
}
ul {
background-color: #B79b58;
overflow: auto;
}
li {
list-style-type: none;
}
<nav>
<ul align="left">
<li><a href="#/contact" class="nav-selections" style="margin-right:35px;">Contact</a></li>
<li><a href="#/about" class="nav-selections">About</a></li>
<li><a href="#/products" class="nav-selections">Products</a></li>
<li><a href="#" class="nav-selections">Home</a></li>
</ul>
</nav>
I have same problem, and i found the answer here.
If your element isn't sticking as expected the first thing to check are the rules applied to the container.
Specifically, look for any overflow property set on any parents of the element. You can't use: overflow: hidden, overflow: scroll or overflow: auto on the parent of a position: sticky element.
Incase you came across this and your sticky is not working - try setting the parent to:
display: unset
Worked for me
Few more things I've come across:
When your sticky element is a component (angular etc)
If the 'sticky' element itself is a component with a custom element-selector, such as an angular component named
<app-menu-bar>you will need to add the following to the component's css::host { display: block; } // or use flexbox
or
app-menu-bar { display: block; } // (in the containing component's css)
Safari on iOS in particular seems to require `display:block` even on the root element `app-root` of an angular application or it won't stick.
If you are creating a component and defining the css inside the component (shadow DOM / encapsulated styles), make sure the
position: stickyis being applied to the 'outer' selector (eg.app-menu-barin devtools should show the sticky position) and not a top leveldivwithin the component. With Angular, this can be achieved with the:hostselector in the css for your component.:host { position: sticky; display: block; // this is the same as shown above top: 0; background: red; }
Other
If the element following your sticky element has a solid background, you must add the following to stop it from sliding underneath:
.sticky-element { z-index: 100; } .parent-of-sticky-element { position: relative; }Your sticky element must be before your content if using
topand after it if usingbottom.There are complications when using
overflow: hiddenon your wrapper element – in general it will kill the sticky element inside. Better explained in this questionMobile browsers may disable sticky/fixed positioned items when the onscreen keyboard is visible. I'm not sure of the exact rules (does anybody ever know) but when the keyboard is visible you're looking at a sort of 'window' into the window and you won't easily be able to get things to stick to the actual visible top of the screen.
Make sure you have:
position: sticky;and not
display: sticky;
Misc usability concerns
- Be cautious if your design calls for for sticking things to the bottom of the screen on mobile devices. On iPhone X for instance they display a narrow line to indicate the swipe region (to get back to the homepage) - and elements inside this region aren't clickable. So if you stick something there be sure to test on iPhone X that users can activate it. A big 'Buy Now' button is no good if people can't click it!
- If you're advertising on Facebook the webpage is displayed in a 'webview' control within Facebook's mobile apps. Especially when displaying video (where your content begins in the bottom half of the screen only) - they often completely mess up sticky elements by putting your page within a scrollable viewport that actually allows your sticky elements to disappear off the top of the page. Be sure to test in the context of an actual ad and not just in the phone's browser or even Facebook's browser which can all behave differently.
This is a continuation of the answers from MarsAndBack and Miftah Mizwar.
Their answers are correct. However, it is difficult to identify the problem ancestor(s).
To make this very simple, simply run this jQuery script in your browser console and it will tell you the value of the overflow property on every ancestor.
$('.your-sticky-element').parents().filter(function() {
console.log($(this));
console.log($(this).css('overflow'));
return $(this).css('overflow') === 'hidden';
});
Where an ancestor does not have overflow: visible change its CSS so that it does!
Also, as stated elsewhere, make sure your sticky element has this in the CSS:
.your-sticky-element {
position: sticky;
top: 0;
}
I had to use the following CSS to get it working:
.parent {
display: flex;
justify-content: space-around;
align-items: flex-start;
overflow: visible;
}
.sticky {
position: sticky;
position: -webkit-sticky;
top: 0;
}
If above dosen't work then...
Go through all ancestors and make sure none of these elements have overflow: hidden. You have to change this to overflow: visible
Sticky Position will not work if your parent is using display flex. As I read this in one solution
Since flex box elements default to stretch, all the elements are the same height, which can't be scrolled against.
So if you are using display: flex; on parent then you will have to add this to sticky element align-self: flex-start; and also set height to auto height: auto;
This is how sticky element class look like
.stick-ontop {
position: -webkit-sticky !important; // for safari
position: sticky !important;
top: 0;
align-self: flex-start;
height: auto;
}
Another very common scenario where position: sticky might not be working is if it's parent has display: flex or display: grid.
What happens in this case is the sticky position is working but you can't see it bcoz the element is stretched completely. Try reducing it's height using align-self: baseline and you'll see the effect.
It seems like that the navbar to be stickied shouldn't be inside any div or section with other content. None of the solution were working for me until I took the navbar out of the div which the navbar shared with another topbar .I previously had topbar and navbar wrapped with a common div.
I know this seems to be already answered, but I ran into a specific case, and I feel most answers miss the point.
The overflow:hidden answers cover 90% of the cases. That's more or less the "sticky nav" scenario.
But the sticky behavior is best used within the height of a container. Think of a newsletter form in the right column of your website that scrolls down with the page. If your sticky element is the only child of the container, the container is the exact same size, and there's no room to scroll.
Your container needs to be the height you expect your element to scroll within. Which in my "right column" scenario is the height of the left column.
The best way to achieve this is to use display:table-cell on the columns. If you can't, and are stuck with float:right and such like I was, you'll have to either guess the left column height of compute it with Javascript.
Attack this Q from other direction.
Imagine this is a game Find the nearest scrolling ancestor.
<!-- sticky not working -->
<h1 style="position: sticky; top:0;">Hello World</h1>
Questions:
- 1/3: The sticky node?
<h1>. - 2/3: The ancestor?
<body>. - 3/3:
<body>scrolling ?FALSE=> "No effect".
Fix: "Sticky is working" (<body> scrolling ? TRUE).
body{
min-height: 300vh;
}
<!-- sticky working -->
<h1 style="position: sticky; top: 0;">Hello World</h1>
With this in mind - here are some "hello world" "famous" scenarios of "not working" sticky :) Most cases relate to one or many of these cases.
Must Read
Case 1: Missing "top" (Easy to fix):
Not working:
/* not working example */
aside{
position: sticky;
background: lightgray;
}
main{
height: 200vh;
}
<aside>
<h2>sticky Aside</h2>
</aside>
<main>
<h1>Article</h1>
<p>Lorem ipsum dolor sit amet, consectetur adipisicing elit. Qui dicta minus molestiae vel beatae natus eveniet ratione temporibus aperiam harum alias officiis assumenda officia quibusdam deleniti eos cupiditate dolore doloribus!
</p>
</main>
Fix (Add top):
aside{
position: sticky;
top: 0;
}
main{
height: 200vh;
}
<aside>
<h2>sticky Aside</h2>
</aside>
<main>
<h1>Article</h1>
<p>Lorem ipsum dolor sit amet, consectetur adipisicing elit. Qui dicta minus molestiae vel beatae natus eveniet ratione temporibus aperiam harum alias officiis assumenda officia quibusdam deleniti eos cupiditate dolore doloribus!
</p>
</main>