Open hunboy opened 7 years ago
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?
@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
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).
I tried to do sticky headers on a table once for a nice UX improvement. I gave up for the very reason you just said. The table was in a div to allow for horizontal scrolling and therefore could not have its headers stuck...
Looks like if you set overflow
to a non-default value for the sticky element ancestor, you would need to set the ancestor height as well. Otherwise, the position: sticky
would not work. For example:
.wrapper {
overflow-x: hidden;
height: 100vh;
}
This works on the chrome 78 (64-bit)
on Win 7
.
Example: codepen
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; }
See demo I need both horizontal scrolling and sticky header.
Hello. Have you found the solution? I have the same require with yours
I was facing same issue, I did try number of CSS solution and finally it works the way you guys are looking for. Here is working codesandbox URL:
https://codesandbox.io/embed/objective-frog-m4imr?fontsize=14&hidenavigation=1&theme=dark
And I am using react table however CSS styling is pretty easy to understand and Don't thing you would face any issue copying over solution even though you don't know react.
@er-parag91 It looks like your code is an example of the "solution" I mentioned above:
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).
You're forcing the table to 50vh
height. If you have a scrollable page, you end up with 2 scrollbars: one for the page, and one for the table. Ugly if you ask me!
Facing same issue. Well seems like this will still not be supported:
Any ancestor between the sticky element and its user-scrollable container with overflow computed as anything but visible/clip will effectively prevent sticking (https://caniuse.com/#feat=css-sticky)
I would prefer to search for a nice workaround instead of a "clean" solution.
As far as I can tell, this request is based on using overflow:hidden
to force a containing to become a BFC so it'll clearfix.
Since we (a) have better ways to force a BFC now that don't interact badly with position:sticky
(such as display: flow-root;
), and (b) rarely if ever need to clearfix now (since that's mostly an artifact of float-based layouts), I think we can safely close this as no change.
@tabatkins hmm, you may have missed the multiple comments about sticky headers on horizontally scrollable tables (a common method for handling large tables on smaller devices). There is also the issue of the common case of having a site wrapper that hides any overflow-x
for off screen navigation and similar animation techniques. That makes it impossible to use sticky elements.
@tabatkins in my practice overflow
is rarely used for BFC, BFC is a thing from the past, when layout was made with float
, for now, we have flex
or even grid
and developers have no reason to use float
and care about BFC.
I agree with @coreyworrell, 90% of my websites have overflow
wrapper to hide offscreen things like protruding images.
I agree – I typically set overflow: hidden;
on a container to prevent my column system from overflowing. A very simplified example is below.
.row {
display: flex;
width: calc(100% + $column_gap);
}
.col {
flex: 1 1 25%;
padding-right: $column_gap;
}
This method keeps everything aligned just right with an accurate gap between each element, but of course means that the .row
almost always overflows the width of its containers. To combat this, I set .page-wrapper { overflow: hidden; }
, which works great, except when I need to use something with position: sticky;
.
Admittedly, my use case could be solved by switching to grid
instead of flex
, but in my testing, I've been unable to replicate the features I need using grid
.
hmm, you may have missed the multiple comments about sticky headers on horizontally scrollable tables
Hmm, I had. I see the issue now.
It seems like the case here is wanting to put horizontal scrollbars on a too-wide table, but not put vertical scrollbars on it when it's taller than 100vh. (Or generally "whatever the height of the screen is", since that's a... difficult-to-predict value on mobile.) And then still get the header rows to be sticky as the table scrolls off, but stay contained to the table itself as normal.
Okay, I'll re-open for this issue.
For the "I'm just using an overflow:hidden
wrapper to prevents things from visually spilling out" case, overflow:clip
achieves that without making it scrollable, and so shouldn't affect stickyness. That value isn't implemented in Chrome yet, but -moz-hidden-unscrollable
is a prefixed name for the value, and if I'm reading previous comments correctly, it does indeed work with sticky (doesn't block stickiness). So I'll consider that part of the issue solved.
(The naming of "hidden" is unfortunate; really it's an "I'm handling scrolling with JS, don't worry about it" value, but it claimed a useful name that makes it sound more general than it is. What we're now calling "clip" should have been named "hidden". ^_^)
The naming of "hidden" is unfortunate; really it's an "I'm handling scrolling with JS, don't worry about it" value, but it claimed a useful name that makes it sound more general than it is.
Maybe a new alias overflow: manual
? 🤔
but not put vertical scrollbars on it when it's taller than 100vh. (Or generally "whatever the height of the screen is", since that's a... difficult-to-predict value on mobile.)
Expanding on this, is the problem just that a max-height
on a table is hard to predict on mobile? (Because 100vh
might be too large depending on what UI is being shown.) If that's the case, would #4329 solve the issue?
Expanding on this, is the problem just that a
max-height
on a table is hard to predict on mobile? (Because100vh
might be too large depending on what UI is being shown.) If that's the case, would #4329 solve the issue?
@tabatkins Not quite. I think you said it correct before:
It seems like the case here is wanting to put horizontal scrollbars on a too-wide table, but not put vertical scrollbars on it when it's taller than 100vh. (Or generally "whatever the height of the screen is", since that's a... difficult-to-predict value on mobile.) And then still get the header rows to be sticky as the table scrolls off, but stay contained to the table itself as normal.
Adding a max-height
can cause double scroll bars (one for window, one for table). It is preferable to allow the table it's auto height.
@tabatkins & @coreyworrell I think you are talking about what I addressed in https://github.com/w3c/csswg-drafts/issues/865#issuecomment-488522567.
"[css-positioned-3] expand sticky logic to allow sticky positioning behavior between nested scrollers, specifically cross axis"
(And honestly, there is a strange precedent for nested sticky logic that shares a containing block, see http://output.jsbin.com/zeyanef/7, best in webkit/firefox. Though, this example doesn't share the containing block through a scroll container, but instead through sticky ancestors.)
This seems to be the only remaining issue in the thread and should simply be broken out, allowing this thread to be closed. Because we have overflow:clip
solving the general ancestor between the sticky element and it's scroll container (containing block) issue. And browsers have now consolidated on a solution for scrollingElement
weirdness with horizontal overflow between the html
& body
elements, where an author just needs to make sure body
isn't an intermediate scroll container between the sticky element and the html
scrollingElement
.
Final note, it really would be a bad idea to retroactively make overflow:hidden
elements do what most in this thread desire for the reasons I stated in https://github.com/w3c/csswg-drafts/issues/865#issuecomment-387908285.
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.
This shows exactly why the specified behavior of overflow:clip
is what is really needed, it just needs to get implemented everywhere. Elements with overflow:hidden
are still scrolling elements even if only programmatically.
Is there a workaround for what @valtlai mentioned? (https://github.com/w3c/csswg-drafts/issues/865#issuecomment-350585274) The link that @jonjohnjohnson shared does not seem to work for native html tables. I too don't want to add a fixed height since the extra scrollbar makes things ugly.
For the "I'm just using an
overflow:hidden
wrapper to prevents things from visually spilling out" case,overflow:clip
achieves that without making it scrollable, and so shouldn't affect stickyness. That value isn't implemented in Chrome yet, but-moz-hidden-unscrollable
is a prefixed name for the value, and if I'm reading previous comments correctly, it does indeed work with sticky (doesn't block stickiness). So I'll consider that part of the issue solved.
@tabatkins: Chrome has closed their issue as won't fix: https://bugs.chromium.org/p/chromium/issues/detail?id=566226
Maybe we should push for them to reopen the issue?
for anyone looking for a solution for native html table i have posted on stackoverflow here:https://stackoverflow.com/questions/63384685/overflowauto-doesnt-work-as-expected-with-positionsticky and also a jsfiddle here: https://jsfiddle.net/uf468ocy/ basically it has a copy table with only the headers which is shown as the header is scrolled out of position.
it possible way i was thinking to make it work better to have ti work natively i would think to put sticky op the scrolling container with overflow such that when the container is scrolled out of view the top "sticks" while the actual container continues to scroll.......if that makes sense
for example say i have a div #data like this
<div id="data" style="overflow:auto;position:sticky;top:0;">
<div id="sticky-element" style="position:sticky;top:0;">
</div>
</div>
then we scrolling would stick data to the top of viewport instead of scrolling it past, while the content of data is then scolled which sticks the element at the top of the data which is the top of the screen or something like that
curremtly if the sticky element is larger than the view port it just scrolls past
How about this solution: https://uxdesign.cc/position-stuck-96c9f55d9526
How about this solution: https://uxdesign.cc/position-stuck-96c9f55d9526
AFAIK, it assumes, that columns have a constant width. Otherwise, if a wider content changes the proportions of columns in the table, then headers can misalign with the content.
(Fork of the codepen from the article with an example of such situation: https://codepen.io/konkit/pen/rNLjjwL)
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/