52

I have this HTML code:

<div class="header">
<div class="desc">Description</div>
<div class="logo"><img src=""/></div>
<div class="navbar"></div></div>

.header has a height of 150px. .navbar has a height of 20px. When the user scrolls, I want .navbar to stick at the top. So I went to the CSS and set position:sticky and top:0. But this didn't work. I initially thought that firefox is not supporting position:sticky, but that's not the case because I was able to see a working demo of it. I googled about it but found nothing helpful. Anyone knows why this is not working?

Wolfuryo
  • 736
  • 1
  • 7
  • 12
  • 10
    Since you don't show your css... Sticky only works if the containing div (header) does not have overflow hidden or auto. Might be something to check. – pinkfloydx33 Aug 06 '17 at 09:18
  • 45
    For anyone else looking into this, `position: sticky` also often doesn't work if the immediate parent is `display: flex` – user56reinstatemonica8 Jan 17 '18 at 20:02
  • 4
    Not really true. Look at the example in this blog: https://alligator.io/css/position-sticky/ The container is a flex element, yet working fine. – Roy Jul 16 '20 at 19:11
  • 15
    I agree with @user56reinstatemonica8. Just wanna add something, it also doesn't work if not only the immediate parent but also any parent or grandfather up to the top element has property like `overflow: hidden` or `overflow: auto`. I came to this conclusion after a lot of head bashing. – Debu Shinobi Jan 09 '21 at 08:20
  • 2
    The "grandfather" mentioning really helps! Thank you @DebuShinobi – NineAllexis Feb 26 '21 at 08:06
  • @NineAllexis Not sure if you're trolling me , I guess I meant grandparents. But welcome if it helped. – Debu Shinobi Feb 26 '21 at 08:12
  • A couple of reasons are listed here https://www.designcise.com/web/tutorial/how-to-fix-issues-with-css-position-sticky-not-working – Shaswat Rungta Oct 10 '22 at 15:56

14 Answers14

123

Position sticky was not working for me due to the body element having overflow-x: hidden; set.

isherwood
  • 58,414
  • 16
  • 114
  • 157
nickspiel
  • 5,170
  • 6
  • 33
  • 48
  • 18
    You just saved me a lot of time. Was doing some restyling and couldn't figure out for the life of me why position sticky stopped working. Turns out a 3rd party was adding overflow styles on html and body. Ugh! – mysticflute Jan 15 '18 at 06:44
  • 1
    Here's a bug report about this https://bugzilla.mozilla.org/show_bug.cgi?id=1329203 – Bjørnar Hagen Sep 11 '18 at 13:37
  • 3
    which basically means e.g. `overflow:initial !important` on some problematic parent could work or one could test it with it – Andreas Covidiot Mar 27 '19 at 12:40
  • 7
    Just want to clarify that is not just with `overflow-x`, it's with **ANY** overflow property, like `overflow-x`, `overflow-y` or `overflow` shorthand. – Ricardo Zea Apr 15 '19 at 13:21
  • You might use `overflow` when you add `display: initial;` – Alp Jan 27 '20 at 10:13
  • 5
    What if I need overflow-x: hidden on body for something else? – Cook88 Jul 29 '20 at 21:22
  • 1
    Ye like Cook88 said what if that overflow has to stay ? What is the solution then ? – strix25 Dec 08 '21 at 22:44
76

The 2 most common culprits why position: sticky; might not work are:

  1. You haven't defined top: 0;, bottom: 0;, left: 0 or something similar
  2. One of the parents of your sticky element has overflow (x or y) set to hidden, scroll, auto or flex.

For me it was the first one.

Dimitris Siakavelis
  • 1,048
  • 9
  • 10
  • 4
    and what is the solution if body has overflow ? Cant just randomly remove it – strix25 Dec 08 '21 at 22:45
  • 1
    @RolandoNiubó same for me, I had a `main` element just after body where overflow-x was set and hence position sticky was not working. – sohammondal Apr 12 '22 at 15:52
  • and the parent of sticky container is flex. add please into the answer. for me help it and overflow – romanown Apr 05 '23 at 06:37
  • I need the body to be flexible because I want to develop a dashboard. So, what is the solution here if I need to use flex in the body and make the sidebar sticky? – Flamingo May 26 '23 at 18:00
  • Even using display:flex I was able to sticky the navbar. The trick is really top: 0; bottom: 0; left: 0;. Thanks very much! – Sandro Stadler May 29 '23 at 21:14
  • In my case the problem was width: 100% in the body – Renan Franca Aug 14 '23 at 19:51
37

It works fine if you move the navbar outside the header. See below. For the reason, according to MDN:

The element is positioned according to the normal flow of the document, and then offset relative to its flow root and containing block based on the values of top, right, bottom, and left.

For the containing block:

The containing block is the ancestor to which the element is relatively positioned

So, when I do not misunderstand, the navbar is positioned at offset 0 within the header as soon as it is scrolled outside the viewport (which, clearly, means, you can't see it anymore).

.navbar {
  background: hotpink;
  width: 100%;
  height: 50px;
  position: sticky;
  top: 0;
}

.header {
  height: 150px;
  background: grey;
}

body {
  height: 800px;
  position: relative;
}
<div class="header">
  <div class="desc">Description</div>
  <div class="logo"><img src="" /></div>
</div>

<div class="navbar"></div>
isherwood
  • 58,414
  • 16
  • 114
  • 157
SVSchmidt
  • 6,269
  • 2
  • 26
  • 37
  • 3
    With the navbar as element of the header like in the question, it is sticky, too. But only until its container ends. Initially it is visible right below "Description" and it will move through the grey header as you scroll down. At the end of the grey area, it will stop as the container (=header) ends. In this answer, the navbar container is body, so this is why it will initially start after the grey header and scroll all the way down. – Neepsnikeep Oct 04 '17 at 12:15
19

To expand from the answers above and some information to make it work with flexbox parent and overflow other than visible (the examples below assume you use vertical - sticky with either top or bottom set to a certain value and position set to sticky):

  1. The most frequent case is you have an ancestor element (not just immediate parent) with overflow property set to something other than visible and as a result there is no space is left to stick around. To quickly find out if this is the case, you can run this script in the browser console (please make sure you change the .your-sticky-element class to your element's selector):

     var stickyElement = document.querySelector('.your-sticky-element');
     var parent = stickyElement.parentElement;
     while (parent) {
         var hasOverflow = getComputedStyle(parent).overflow;
         if(hasOverflow != 'visible') {
             console.log(hasOverflow, parent);
         }
         parent = parent.parentElement;
     } 
    

    SOLUTION:

    a) If you found there is overflow set, and you can remove it, this should solve it

    b) If you have to keep your overflow setting, you have to make the parent element's height higher than the sticky element's height. If the parent element has no height or the sticky element fills up all the height, it means there is simply no place to stick within when the page is scrolled. It doesn't need to an explicit height (vertical), but you can inspect to see if your sticky element has extra space left after itself.

  2. Parent is not higher than the sticky element to leave extra space. This particular case can be caused by different circumstances but the solution to this is the same above, please see 1.b

  3. If your sticky element's parent is a flexbox (align-items has default value of normal) or grid, and if the sticky element itself doesn't have a proper align-self set, there will be no space left for the sticky element to hold when scrolling (for example, if it is align-self: stretch or auto [default value]). This is because the child element is stretched to fill up the height of the parent.

    SOLUTION:

    In this case, align-self: flex-start set for the sticky element can fix the problem because in the element will stand at the start, leaving extra space after itself.

Guide: There are much more complex circumstances both in the case of flexboxes and without it, but the general rule of thumb is your sticky element needs space within the parent to be sticky when scrolled.

Selay
  • 6,024
  • 2
  • 27
  • 23
  • 1
    I don't know what kind of wizardry this is, but it worked!! – Bernardo Dal Corno Apr 23 '21 at 23:27
  • Hmm have overflow: hidden; on body parent of sticky has bigger hight then sticky and still does not work :/ – strix25 Dec 08 '21 at 22:51
  • 2
    `align-self: flex-start` fixed my problem. Thank you – bubbakk Jul 11 '22 at 13:40
  • It's worth noting that the caveats about flex apply to grid too. I was able to get my grid child item to be sticky by adding `align-self: flex-start` – JakeParis Dec 07 '22 at 20:26
  • You are a genius! This fixes my problem (when the parent is `flex`), and now I can have a sticky sidebar in my dashboard project. Just a note: when using align-self: flex-start, the sidebar doesn't take the full height. So, I added height: 100vh to my sidebar to fix this problem. – Flamingo May 26 '23 at 18:07
  • By any chance any one facing this but not on vertical but horizontal scroll, what should the align would be in this case, I mean direction should be row and I am assuming that flex-start and end should accommodate but not workin on my side :/ – dgnF Jul 26 '23 at 23:25
5

Somehow your code only works when the .navbar element is not inside another container like the header. I moved it out and then it works fine. I created a codepen snippet for that, check it out

<header>
    <div class="logo">Logo</div>
    <div class="description"><div>Lorem ipsum dolor sit amet consectetur adipisicing elit. Quo, veritatis.</div></div>
</header>
<div class="navbar">
    <ul>
        <li><a href="#">navitem1</a></li>
        <li><a href="#">navitem2</a></li>
        <li><a href="#">navitem3</a></li>
        <li><a href="#">navitem4</a></li>
    </ul>
</div>

Right now position:sticky is supported quite good as you can see on canIuse. Of course IE currently has no support but the new Edge version will bring full support for this! I found some interesting articles about this topic:

But there are good news on the horizon. I think better browser support will follow the next time.

Gerrit Halfmann
  • 1,332
  • 8
  • 17
3

Adding more content after nav inside header provides sticky behavior, but only for a moment - if the user scrolls down too much, nav will disappear with header, since it can't jump out below header's bottom border.

Thus, the only solution with pure CSS is to put nav inside element that is partially visible even after the user scrolls to the bottom of the page (directly inside body or inside some sort of container that spans to the bottom of the page or at least to the footer).

If this solution is not possible, the other way is to use JavaScript. Before transitioning to CSS, I used the following code (found similar jQuery solution somewhere long time ago, don't remember where, so the credit goes to the anonymous author; Vanilla JS can be easily obtained from this):

$(document).ready(function () {
    var sticky_navigation_offset_top = $('nav').offset().top;
    var sticky_navigation = function () {
        var scroll_top = $(window).scrollTop();
        if (scroll_top > sticky_navigation_offset_top) {
            $('nav').css({
                'position': 'fixed',
                'top': 0,
                'left': 0,
                'right': 0,
                'margin-left': 'auto',
                'margin-right': 'auto'
            });
        } else {
            $('nav').css({
                'position': 'relative'
            });
        }
    };
    sticky_navigation();
    $(window).scroll(function () {
        sticky_navigation();
    });
});
2

Looks like if you try to set sticky a container which has many children nodes inside, instead of them being wrapped in a div, and the parent of sticky container is flex, then it will not sticky. Just wrap the childs in a div fixed it for me.

SkyzohKey
  • 755
  • 7
  • 16
1

Your HTML code as it is and write CSS class for navigation bar:

.header {
  height: 150px;
  background-color: #d1d1d1;
}

.navbar {
  background: #999;
  border-bottom: 1px solid #333;
  border-top: 1px solid #333;
  color: #FFF;
  margin: 0;
  padding: 2px 0 0 12px;
  position: sticky;
  top: -1px;
}
<div class="header">
  <div class="desc">Description</div>
  <div class="logo"><img src="" /></div>
  <div class="navbar"></div>
</div>

Hope this will help

isherwood
  • 58,414
  • 16
  • 114
  • 157
M Thomas
  • 1,062
  • 1
  • 10
  • 12
  • I already tried this, without any succes. I tried to add position:sticky and top:0 to the .header element and it works, but that's not what I want. – Wolfuryo Aug 06 '17 at 09:15
  • I tried moving out the navbar from the header container, it is working – M Thomas Aug 06 '17 at 09:29
1

Many answers have said that its either that you've not set top/bottom/left/right for the sticky element, or your immediate parent has overflow set to hidden, scroll or auto.

However, if you want the immediate parent to clip any overflow while also having the sticky element work, you cannot use overflow: hidden;

For that you may set it as overflow: clip; instead for the immediate parent.

Granted, clip and hidden are not the same thing, but depending on your use case, this may be exactly what you're looking for.

0

Met some not evident behaviour of horizontal sticky: if width is 100%, then sticky does not work. Width should be less, then container size.

Pavel
  • 2,602
  • 1
  • 27
  • 34
0

My sticky header would only partly work ... after a couple of scrolls it would disappear but would work initially

It appears the problem was that I had the parent set to height 100%.

I didn't actually need this as the body one was enough so I removed and it and all was good.. sticks forever

enter image description here

Although this now breaks my footer from staying on the bottom when their is no content!

72GM
  • 2,926
  • 3
  • 27
  • 33
0

No huge compromises of the HTML structure need to be made to fix this issue. Simply add display: inline; to all of the sticky element's parents up until you get to the element you wish the sticky element to stick to.

Danii
  • 167
  • 3
  • 9
0

Just to add something to @user56reinstatemonica8 great point...

If immediate parent of sticky node has display: flex sticky positioning could not work.

My guess is that culprit is align-items: stretch as default.
In a flex-direction: row scenario, align-items: stretch let children's height grow so that they are equal height.

So, to overcome this and make sticky work as expected with display: flex you can:

  • define align-items as center | start | baseline to immediate parent that has display: flex.
  • define align-self as center | start | baseline to sticky node.
  • define an explicit height to sticky node.
Jacopo Marrone
  • 77
  • 1
  • 10
0

As mentioned on previous answers, one of the most common issues is forgeting to define one of the following properties top bottom along with your position: 'sticky'.

The issue I had was caused by the container being defined with height: 100%; instead of min-height: 100%; or something similar.

.container {
  min-height: 100vh;
  display: flex;
  flex-direction: column;
}

header {
  background: #eeeeeeee;
  position: sticky;
  top: 0px;
}

main {
  flex-grow: 1;
}

footer {
  background: #eeeeeeee;
  position: sticky;
  bottom: 0px;
}
<div class="container">
  <header>header</header>
  <main>
    Lorem ipsum dolor sit amet consectetur adipisicing elit. Eum repellat, vitae natus ipsum qui iste, placeat provident nemo voluptas magnam, architecto explicabo molestias culpa! Eos voluptate odit ut dicta asperiores aliquam fugiat. Similique soluta velit fugit ex magnam nemo hic delectus, ratione sequi ea commodi corrupti a voluptatibus non quos? Iure eum atque vel! Assumenda, libero. Labore, quibusdam nesciunt, soluta ullam quis consequatur dolore, blanditiis veritatis nisi impedit consectetur perspiciatis. Sit, amet quidem dolore recusandae voluptate aperiam! Doloribus porro rem suscipit minus. Voluptate consequatur laboriosam a aspernatur omnis ullam consectetur dignissimos, aliquam quasi eligendi, ipsam non laborum quam quisquam rem, porro explicabo eos voluptas? Maxime aliquam quam quas dolorum a dolorem amet, nulla quidem sunt itaque eveniet dignissimos explicabo velit sint earum, quos asperiores dolor ad? Accusamus similique inventore, sunt vero ullam iusto neque necessitatibus veniam minima. Quasi ipsa quod rerum deleniti laboriosam accusamus distinctio quaerat cumque quas? Dolorem beatae, totam dolores repudiandae esse error vero aut, quam impedit delectus natus quis libero tenetur fugiat illo officiis, porro amet. Velit a praesentium totam amet deleniti architecto necessitatibus dolore sequi id, atque numquam sunt harum exercitationem illum facere debitis officiis nihil repellat cupiditate maiores? Vero hic quasi accusamus provident tempora quo error magni voluptatibus harum, adipisci rem repellat facilis, quae commodi tenetur, vitae quos illo aspernatur necessitatibus? Eligendi officia voluptas, ratione est natus ut saepe tenetur! Alias facilis obcaecati repudiandae hic natus distinctio sequi doloremque blanditiis eos quasi, ad odio dolorem iste, voluptatibus ullam, praesentium vel accusamus beatae id maxime inventore? Laudantium cupiditate eum eos quae nulla, veritatis sunt tenetur saepe placeat libero quaerat iusto a? Eos blanditiis sit animi reprehenderit nemo? Adipisci optio harum quas sit distinctio assumenda tempora inventore enim aliquid. Earum nisi nemo perspiciatis. Harum suscipit, adipisci ullam porro, quo possimus eaque veniam corporis, cumque ut aliquid voluptates ipsam. Aperiam beatae necessitatibus optio dicta fugiat aspernatur aliquid assumenda cumque placeat similique. Natus fugiat facilis quae, voluptatibus deserunt repellendus voluptates blanditiis illo voluptatem iure, quasi veritatis labore aliquid perspiciatis nesciunt architecto. Saepe incidunt sequi consectetur! Rem asperiores, labore saepe vitae error totam mollitia praesentium ratione ducimus, quidem earum blanditiis animi vero optio officiis perferendis dolores, aperiam impedit molestias expedita. Molestiae quod ipsa totam ad! Quis tenetur cum, quas sunt dolore, facere qui ipsam expedita, eum cupiditate veritatis libero. Inventore quisquam, totam facilis eum numquam iste odio magnam in excepturi vero? Illum eveniet suscipit quis aliquid odio nobis architecto voluptatibus non! Facere ad debitis commodi numquam excepturi consectetur reiciendis ipsum nulla libero optio est a labore qui at accusamus nostrum modi, consequuntur eveniet atque culpa dicta doloremque unde? Suscipit, dolore, recusandae dolores ipsam cupiditate quas qui esse labore doloribus repudiandae mollitia iure sed ipsum. Reiciendis porro quaerat consequuntur illo cumque odit, facere distinctio sunt repudiandae laudantium iusto eos aut pariatur, doloribus eligendi consequatur minima non nisi, quas ducimus esse perspiciatis beatae sequi? Autem quis recusandae cumque, ratione dicta eaque asperiores nesciunt obcaecati quae debitis aliquam non, reprehenderit vitae. Optio nobis ipsum autem, blanditiis nulla asperiores sequi rem quo laboriosam incidunt?
  </main>
  <footer>footer</footer>
</div>
Gabriel Brito
  • 1,003
  • 2
  • 16
  • 26