98

In the following snippet, there is a sticky div positioned inside a container. It sticks to the top of the scrolling panel while staying inside its container all the time. This is the same behavior as that of the UITableView headers on iOS, where the headers stay visible until the next header is at the top.

In the second snippet, everything is the same except that the container has an overflow:hidden CSS rule. This seems to prevent the position:sticky behavior from working correctly.

.parent {
  position: relative;
  background: #ccc;
  width: 500px;
  height: 150px;
  overflow: auto;
  margin-bottom: 20px;
}

.hidden-overflow {
  overflow: hidden;
}

.sticky {
  position: sticky;
  background: #333;
  text-align: center;
  color: #fff;
  top: 10px;
}
<div class="parent">
  <div>
    <div class="sticky">
      Hi, I am a sticky inside the container which contains the first paragraph.
    </div>
    <p>
      Lorem ipsum dolor sit amet, consectetur adipiscing elit. Vivamus volutpat sed metus et porttitor. Integer bibendum lacus eget massa ultricies fermentum. Donec cursus magna eu congue posuere. Sed eget ligula quam. Sed laoreet enim sapien, eget volutpat nisl pellentesque vel. Nulla id dolor sed dolor sodales tristique. Curabitur feugiat massa sed massa bibendum semper et ac orci. In imperdiet nibh quis iaculis viverra. Class aptent taciti sociosqu ad litora torquent per conubia nostra, per inceptos himenaeos. Quisque vestibulum, nunc non volutpat tristique, nisl nisi volutpat nibh, quis pulvinar purus ex nec justo. Sed a cursus turpis. Quisque nulla odio, lacinia quis vestibulum sit amet, elementum laoreet nisi. Etiam aliquet ligula sagittis,
    consectetur ipsum sit amet, sodales augue.
    </p>
  </div>
  <p>
    Lorem ipsum dolor sit amet, consectetur adipiscing elit. Vivamus volutpat sed metus et porttitor. Integer bibendum lacus eget massa ultricies fermentum. Donec cursus magna eu congue posuere. Sed eget ligula quam. Sed laoreet enim sapien, eget volutpat
    nisl pellentesque vel. Nulla id dolor sed dolor sodales tristique. Curabitur feugiat massa sed massa bibendum semper et ac orci. In imperdiet nibh quis iaculis viverra. Class aptent taciti sociosqu ad litora torquent per conubia nostra, per inceptos
    himenaeos. Quisque vestibulum, nunc non volutpat tristique, nisl nisi volutpat nibh, quis pulvinar purus ex nec justo. Sed a cursus turpis. Quisque nulla odio, lacinia quis vestibulum sit amet, elementum laoreet nisi. Etiam aliquet ligula sagittis,
    consectetur ipsum sit amet, sodales augue.
  </p>
  <p>
    Integer congue augue a quam tincidunt, vitae dictum sem iaculis. Proin feugiat nibh vitae leo facilisis, eget laoreet augue dictum. Nunc facilisis tempor feugiat. Aenean eget interdum diam. Maecenas non risus iaculis, scelerisque ipsum eu, facilisis urna.
    Integer velit justo, vestibulum vel vulputate vel, bibendum eu lorem. Phasellus viverra nisl a mi pretium eleifend.
  </p>
</div>
<div class="parent">
  <div class="hidden-overflow">
    <div class="sticky">
      Hi, I am another sticky in the container which contains the first paragraph, but my container has overflow:hidden.
    </div>
    <p>
      Lorem ipsum dolor sit amet, consectetur adipiscing elit. Vivamus volutpat sed metus et porttitor. Integer bibendum lacus eget massa ultricies fermentum. Donec cursus magna eu congue posuere. Sed eget ligula quam. Sed laoreet enim sapien, eget volutpat nisl pellentesque vel. Nulla id dolor sed dolor sodales tristique. Curabitur feugiat massa sed massa bibendum semper et ac orci. In imperdiet nibh quis iaculis viverra. Class aptent taciti sociosqu ad litora torquent per conubia nostra, per inceptos himenaeos. Quisque vestibulum, nunc non volutpat tristique, nisl nisi volutpat nibh, quis pulvinar purus ex nec justo. Sed a cursus turpis. Quisque nulla odio, lacinia quis vestibulum sit amet, elementum laoreet nisi. Etiam aliquet ligula sagittis,
    consectetur ipsum sit amet, sodales augue.
    </p>
  </div>
  <p>
    Lorem ipsum dolor sit amet, consectetur adipiscing elit. Vivamus volutpat sed metus et porttitor. Integer bibendum lacus eget massa ultricies fermentum. Donec cursus magna eu congue posuere. Sed eget ligula quam. Sed laoreet enim sapien, eget volutpat
    nisl pellentesque vel. Nulla id dolor sed dolor sodales tristique. Curabitur feugiat massa sed massa bibendum semper et ac orci. In imperdiet nibh quis iaculis viverra. Class aptent taciti sociosqu ad litora torquent per conubia nostra, per inceptos
    himenaeos. Quisque vestibulum, nunc non volutpat tristique, nisl nisi volutpat nibh, quis pulvinar purus ex nec justo. Sed a cursus turpis. Quisque nulla odio, lacinia quis vestibulum sit amet, elementum laoreet nisi. Etiam aliquet ligula sagittis,
    consectetur ipsum sit amet, sodales augue.
  </p>
  <p>
    Integer congue augue a quam tincidunt, vitae dictum sem iaculis. Proin feugiat nibh vitae leo facilisis, eget laoreet augue dictum. Nunc facilisis tempor feugiat. Aenean eget interdum diam. Maecenas non risus iaculis, scelerisque ipsum eu, facilisis urna.
    Integer velit justo, vestibulum vel vulputate vel, bibendum eu lorem. Phasellus viverra nisl a mi pretium eleifend.
  </p>
</div>

(Snippet adapted from @Daniel's here)

Why doesn't position:sticky work in a container with overflow:hidden?

Community
  • 1
  • 1
Jonas Sourlier
  • 13,684
  • 16
  • 77
  • 148

4 Answers4

83

overflow: hidden is not preventing position: sticky from working. But if you set overflow to hidden on any ancestor of your sticky element, then this ancestor element will be the scrolling container for your sticky element. If you switch the overflow value on your ancestor from hidden to scroll and scroll this ancestor (not the window), then you can see that sticky is still working.

See also https://github.com/wilddeer/stickyfill#pro-tips:

Any non-default value (not visible) for overflow, overflow-x, or overflow-y on any of the predecessor elements anchors the sticky to the overflow context of that predecessor. Simply speaking, scrolling the predecessor will cause the sticky to stick, scrolling the window will not. This is expected with overflow: auto and overflow: scroll, but often causes problems and confusion with overflow: hidden.

Or http://www.coreyford.name/files/position-sticky-presentation/:

The box's position depends on its containing block (established as for position:static) as well as its scrolling container, defined by the nearest ancestor in the same document with a computed value for 'overflow-x' or 'overflow-y' other than 'visible', or the viewport if no such ancestor exists.

Or the CSS Positioned Layout Module Level 3 W3C Working Draft:

A stickily positioned box is positioned similarly to a relatively positioned box, but the offset is computed with reference to the nearest ancestor with a scrolling box, or the viewport if no ancestor has a scrolling box.

chaenu
  • 1,915
  • 16
  • 32
  • 7
    I should point out that `sticky` with ancestor `overflow` from `hidden` to `scroll` will only work if the height of the ancestor container is set, in which case you would be able to scroll the container not the window. – Anjan Biswas Aug 30 '18 at 06:44
  • i wonder if we could put the ancestor as sticky and some how scroll that ancestor once it starts sticking – Fuseteam Aug 10 '20 at 17:25
  • 3
    OK. Is it possible to prevent this when using `overflow-x: hidden;`? – Eliezer Berlin Nov 16 '20 at 16:58
  • No, any non-default value (not visible) for overflow, overflow-x, or overflow-y on any of the predecessor elements anchors the sticky to the overflow context of that predecessor. – chaenu Nov 17 '20 at 17:17
  • So essentially u are left with your site either having horizontal scrollbar and position sticky functioning, or no horizontal scrollbar but no position sticky functionality. CSS conflict of the century. – ints Jun 27 '23 at 17:12
78

It's been a few years since this question was originally posted, now there is another way to hide overflowing content:

contain: paint;

https://developer.mozilla.org/en-US/docs/Web/CSS/contain

seahorsepip
  • 4,519
  • 1
  • 19
  • 30
  • 1
    You mean `contain`? – Mosh Feu Mar 09 '22 at 12:41
  • 1
    @MoshFeu woops (updated) – seahorsepip Mar 09 '22 at 14:31
  • 4
    This works, but it will mess up the fixed positioning of any item inside it. https://developer.mozilla.org/en-US/docs/Web/CSS/Containing_block#identifying_the_containing_block – noiseymur May 10 '22 at 12:02
  • @noiseymur i'm in trouble with this, too :( is there any way to use absolute position inside a `contain` normally? thank u. – noctrlz Nov 07 '22 at 03:40
  • 2
    It's a really bad idea to use `contain: paint` just for clipping overflow content, because it has other side effects. Instead use `overflow: clip` – ydaniv Mar 07 '23 at 21:12
  • 1
    @ydaniv Hey I just listened to your advice and used `overflow: clip` instead and it works great! Do you care to explain how `overflow: clip` is different from `overflow: hidden` and why is it a better choice than `contain: paint` ? – xperator Mar 28 '23 at 12:06
  • You can read the answer above which is correct. And also note that `overflow: hidden` means the container is still scrollable, but only via script, and it scrollbars are hidden to the user. – ydaniv Mar 30 '23 at 06:54
16

I'm not sure this will work in all cases but I've run up against this and was able to get around the issue by replacing overflow: hidden; with clip-paths.

.parent {
    /*overflow: hidden; removed */
    position: absolute; /*this is required for clip-paths to work*/
    -webkit-clip-path: inset(0); /* safari*/
    clip-path: inset(0);
    clip: rect(0px, auto, auto, 0px); /* IE11/Edge (not that IE11 supports sticky anyway!) */
}

As far as having to add position absolute, wrapping the overflow:hidden element in another position: relative element and then adding top, bottom, left and right: 0; should make it fill it's parent container.

marmite
  • 471
  • 3
  • 13
  • 3
    https://caniuse.com/#search=clip-path in case anyone's wondering about browser compatibility with this clever approach. – simmer Jul 12 '19 at 21:20
16

I ran into this issue and found an alternative solution, to use overflow: clip instead of overflow: hidden. As far as I can tell they work in almost the same way, except the anchor point of the sticky element is unaffected when using clip. The only problem is that as of Nov 2022 overflow: clip has limited (~80%) browser support: https://caniuse.com/mdn-css_properties_overflow_clip

Eric Aya
  • 69,473
  • 35
  • 181
  • 253
sherlock
  • 367
  • 5
  • 15
  • 1
    `overflow: clip` has better support now. I found that I needed to use `display: flow-root` alongside this in order to get behavior similar to `overflow: hidden`. – korisu Jan 27 '23 at 22:42
  • This is the only thing that worked in my case. Thank you. – dipole_moment Mar 11 '23 at 03:06