Why does `overflow:hidden` prevent `position:sticky` from working?
Asked Answered
P

4

109

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?

Palmirapalmistry answered 11/5, 2017 at 8:12 Comment(0)
C
91

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

Columbary answered 15/1, 2022 at 14:22 Comment(7)
You mean contain?Cai
@MoshFeu woops (updated)Columbary
This works, but it will mess up the fixed positioning of any item inside it. developer.mozilla.org/en-US/docs/Web/CSS/…Sweetbrier
@Sweetbrier i'm in trouble with this, too :( is there any way to use absolute position inside a contain normally? thank u.Unnumbered
It's a really bad idea to use contain: paint just for clipping overflow content, because it has other side effects. Instead use overflow: clipAlidaalidade
@Alidaalidade 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 ?Lilienthal
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.Alidaalidade
M
87

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.

Munition answered 5/7, 2017 at 14:51 Comment(5)
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.Willena
i wonder if we could put the ancestor as sticky and some how scroll that ancestor once it starts stickingRouter
OK. Is it possible to prevent this when using overflow-x: hidden;?Avouch
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.Munition
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.Susan
K
28

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

Kodiak answered 16/11, 2022 at 14:32 Comment(2)
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.Royalty
This is the only thing that worked in my case. Thank you.Abbyabbye
O
17

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.

Outport answered 25/4, 2019 at 15:21 Comment(1)
caniuse.com/#search=clip-path in case anyone's wondering about browser compatibility with this clever approach.Algology

© 2022 - 2024 — McMap. All rights reserved.