csswg-drafts
csswg-drafts copied to clipboard
[css3 positioning] support position:sticky inside an overflow:hidden|auto on general parents
css3 position
Currently the position:sticky element exclusively works when the all of general parents are overflow:visible. This is problematic a little whilst we use overflow:hidden trick for clearfix etc.
Testcase attached. Here is a simplesample, how is the layout broken when we change the overflow to visible, however sticky starts to work in that case. I detected, all of general parent-elements in the parent-path must be overflow: visible, which is weird a little. Any overflow:hidden in the parent-path kills the sticky.
ER: sync somehow the spec to allow sticky subcontainers inside a overflow:hidden general parent.
testcase: https://jsfiddle.net/utasir/rmmkxq62/11/
mozbugzilla link : https://bugzilla.mozilla.org/show_bug.cgi?id=1329203
maybe not really a bug but by implementation. Check this specs out
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.
The official spec for position: sticky is at W3C and there is no mention of overflow: hidden
. I do not see a reason why an element with position: sticky
cannot be sticky inside <body>
with overflow-x: hidden
. Please fix it.
This spec seems to have changed quite a bit since the implementation in Gecko. It no longer mentions scrolling ancestors, it exclusively talks about containing blocks now. I agree that the current writing of the spec would allow crossing overflow:hidden / auto descendants when computing the offset. But I don't know what the rationale behind that change to the spec was, or whether implementing that change is web compatible.
+1, I find this a very strange limitation especially when the element in question is not actually hidden. It makes it much more fragile to use it given that a change to a parent container / component could break sticky behaviour entirely
It would be nice to make this work:
<div class="table-wrapper">
<table>
<tr><th>Foo</th><th>Bar</th></tr>
<tr><td>sin</td><td>cos</td></tr>
<tr><td>tan</td><td>baz</td></tr>
...
</table>
</div>
.table-wrapper {
overflow-x: auto;
}
th {
position: sticky;
top: 0;
}
I need both horizontal scrolling and sticky header.
I'm building a table template in SCSS which requires this functionality in many situations.
Thankfully, everything now works in Chrome [63], Edge [41], Firefox [59] and Safari [11]. Safari requires -webkit-sticky, and Firefox 59 is the current dev version (unreleased).
Here's a basic test case for overflow-x and overflow-y support: https://codepen.io/SimplyPhy/pen/oEZKZo
@SimplyPhy was going to comment and say safari just needed prefix for sticky, but now I see you updated your comment. Though safari still has an issue 'sticking' your td:first-child {top: 0}
, I'm guessing because it doesn't calculate the top edge of it's parent tr
like other browsers. But if you remove that property declaration, the behavior is probably how you want it?
Yup, thanks @jonjohnjohnson and nice find.
I have the following rule:
html, body {
overflow-x: hidden;
}
and because of it, I'm not able to use position: sticky;
at all. I'm trying to add some submit buttons on a form, and have them sticky to the bottom of the window position: sticky; bottom: 0;
when outside the viewport. It works great and I love the feature, but this overflow-x rule prevents it from working. It sounds very similar to what @niutech mentioned.
@natematykiewicz though not ideal, I believe all current browser versions support sticky behavior if you alter your DOM structure so that the scrolling element is inside the body/html, filling out the screen. This does make it so browsers that resize the viewport on scrolling of the document.scrollingElement
won't resize, such as ios safari. Notice the example code @SimplyPhy provided with for his table utility. Hope that helps until the spec is figured out.
@jonjohnjohnson my previous comment was that I have overflow-x: hidden;
on the body and html tag, and that prevents position: sticky;
from working on anything. I did just realize that if I put the overflow-x: hidden;
on only the body or the html (but not BOTH), then it works (this is in Chrome on a Mac). So, maybe I can actually adjust my CSS to get the best of both worlds. It's just odd that preventing the body and html from horizontally scrolling means that I can no longer get elements to stick to the top of the screen. I could see overflow-y: hidden;
causing problems, but not overflow-x: hidden;
.
@natematykiewicz
The computed values of both overflow-x
& overflow-y
are...
as specified, except with
visible
computing toauto
if one ofoverflow-x
oroverflow-y
is notvisible
- css-overflow-3/#overflow-properties
This is what causes our issue and is spec compliant.
Furthermore, check your "(but not BOTH)" solution in safari, including iOS, because that approach hasn't historically given people what they have sought out. -> overflow-xhidden-doesnt-prevent-content-from-overflowing.... Again, the most robust solution is to scroll an element WITHIN the body, not the body/html/document. Good luck.
Just wanted to make a note for others about how allowing general overflow: hidden
ancestors to not be the "scrolling context" for a sticky element isn't always desirable. When using a modal view that programmatically turns off/on scrolling with hidden
/auto
a sticky element would jump around the screen between the swapping scrolling contexts.
Also, when we (eventually) have overflow: clip
implemented everywhere, this should no longer be an issue?
- #1971 - Is the box a scroll container if only one of 'overflow-x' or 'overflow-y' is 'clip'?
- https://drafts.csswg.org/css-overflow-3/#valdef-overflow-clip
@SimplyPhy in your codepen (https://codepen.io/SimplyPhy/pen/oEZKZo ) on the table,Is there any way to restrict the scroll on header content. Scroll looks odd on the header.
For anybody stumbling upon this issue via google, here's a workaround (at least for my case) using a polyfill: https://stackoverflow.com/a/52420677/4903358
For my use case, one of the ancestors in the DOM had overflow-x: hidden;
. My goal was to simply hide horizontal scrollbar, so this may not apply to your use case.
The way I fixed it was removing overflow-x: hidden;
from that element in the DOM and adding it to body instead!
body {
overflow-x: hidden;
}
@protoEvangelion I realized after trying that the solution does not work on mobile browsers :( https://stackoverflow.com/questions/14270084/overflow-xhidden-doesnt-prevent-content-from-overflowing-in-mobile-browsers
@damienroche I believe androids webview behaves according to spec here, but it's iOS that doesn't. If you want to chip in and voice concern about their noncompliance here's the public ticket.
WebKit Bugzilla - Bug 153852 - with overflow:hidden CSS is scrollable on iOS
Also, when we (eventually) have
overflow: clip
implemented everywhere, this should no longer be an issue?
It does sound like overflow: clip
is the answer here. What is the current position of this standard? I don't see any browsers implementing it. 🤔
Gecko implements overflow: -moz-hidden-unscrollable
which is effectively overflow: clip
. Don't know the background on why it's not unprefixed.
The fact that overflow: hidden;
on an ancestor makes this container become the new scrolling container for the sticky element, takes away the opportunity to clip the sticky container in any way.
I have a use case where the height of the sticky element and the height of its parent are unknown. I want the sticky element to be sticky on browser scroll. But I dont want the sticky element to overflow its parent. With the current spec this seems to be impossible. But I believe that this is a common use case.
I could fix my problem for Firefox by using overflow: -moz-hidden-unscrollable;
. But what would be the valid way to do this?
No clue for in combination with scroll-snap on parent. Page with 100vh per section, sticky as dynamic css for header nav part of first section overflows the scroll bar.
Additionally toying with width and max-width values and units leaves me the impression that browser chrome comes up with magical t.i. spec-undefined values.
It would be nice to make this work:
<div class="table-wrapper"> <table> <tr><th>Foo</th><th>Bar</th></tr> <tr><td>sin</td><td>cos</td></tr> <tr><td>tan</td><td>baz</td></tr> ... </table> </div>
.table-wrapper { overflow-x: auto; } th { position: sticky; top: 0; }
I need both horizontal scrolling and sticky header.
Hello. Have you found the solution? I have the same require with yours
@WangXBruc Unfortunately not. 🙁
@valtlai @WangXBruc I don't exactly condone this fix, but if you really need some sort of nested separate scroller with separate axis treatment, this is the best approach yet. https://uxdesign.cc/position-stuck-96c9f55d9526
@OliverJAsh @emilio Gecko bug for renaming/implementing overflow: clip
.
https://bugzilla.mozilla.org/show_bug.cgi?id=1531609
@Baedda Tangentially...
The fact that overflow: hidden; on an ancestor makes this container become the new scrolling container for the sticky element, takes away the opportunity to clip the sticky container in any way.
There are other ways to "clip" the sticky container, by using clip-path
, even though the "overflow" can affect the geometry of scrollable content, it still behaves well in most cases.
@joma74
No clue for in combination with scroll-snap on parent. Page with 100vh per section, sticky as dynamic css for header nav part of first section overflows the scroll bar.
You can use calc()
to offset a "fullscreen" height with a sticky nav. But some browsers (iOS safari) don't report 100vh
as the height of the unscrolled viewport. (https://nicolas-hoizey.com/2015/02/viewport-height-is-taller-than-the-visible-part-of-the-document-in-some-mobile-browsers.html)
@Baedda @joma74 check these demos for examples of sticky/clip-path/calc()/vh
- https://jsbin.com/tedowel/edit
- https://jsbin.com/lefekiv/edit
- https://jsbin.com/subojom/edit
UPDATE Demos are best viewed in webkit, which has the most robust clip-path
support.
@jonjohnjohnson The link you posted (https://uxdesign.cc/position-stuck-96c9f55d9526) requires javascript (basically, attaching a scroll listener which updates the positioning of other elements). I don't think this is an acceptable workaround, especially from a performance perspective.
@joshjg I agree – it's a solution, but given that position: sticky
is a native CSS feature, we shouldn't need to rely on JavaScript for this use case.
@joshjg @JacobDB I provided that link in response to a case which is a bit different/more than this filing, so I'd suggest opening up a separate issue. Something along the lines of...
"[css-positioned-3] expand sticky logic to allow sticky positioning behavior between nested scrollers, specifically cross axis"
Especially since it seems a lot of folks have shown support for the use case @valtlai provided.
I want to emphasize my support for @valtlai's request as well:
.table-wrapper {
overflow-x: auto;
}
th {
position: sticky;
top: 0;
}
Currently you have to choose between having the table scroll horizontally, or sticking the headers. You can't have both, which is a shame.
The only "solution" that does not involve JavaScript is forcing the table to a given height, which is a really ugly and counter-user-friendly solution with its 2 scrollbars, one for the page and one for the table (especially when the table is the central UI element in the page).