csswg-drafts icon indicating copy to clipboard operation
csswg-drafts copied to clipboard

[css3 positioning] support position:sticky inside an overflow:hidden|auto on general parents

Open hunboy opened this issue 8 years ago • 82 comments

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/

hunboy avatar Jan 06 '17 21:01 hunboy

mozbugzilla link : https://bugzilla.mozilla.org/show_bug.cgi?id=1329203

hunboy avatar Jan 06 '17 22:01 hunboy

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.

pedi avatar Mar 31 '17 07:03 pedi

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.

niutech avatar Aug 23 '17 16:08 niutech

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.

mstange avatar Aug 23 '17 18:08 mstange

+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

sidhu663 avatar Oct 03 '17 05:10 sidhu663

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.

valtlai avatar Dec 10 '17 22:12 valtlai

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 avatar Feb 11 '18 04:02 SimplyPhy

@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?

jonjohnjohnson avatar Feb 11 '18 05:02 jonjohnjohnson

Yup, thanks @jonjohnjohnson and nice find.

SimplyPhy avatar Feb 11 '18 16:02 SimplyPhy

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 avatar Feb 21 '18 02:02 natematykiewicz

@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 avatar Feb 24 '18 00:02 jonjohnjohnson

@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 avatar Apr 05 '18 23:04 natematykiewicz

@natematykiewicz

The computed values of both overflow-x & overflow-y are...

as specified, except with visible computing to auto if one of overflow-x or overflow-y is not visible - 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.

jonjohnjohnson avatar Apr 06 '18 01:04 jonjohnjohnson

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?

jonjohnjohnson avatar May 09 '18 23:05 jonjohnjohnson

@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.

sudheer-gowrigari avatar Jul 25 '18 06:07 sudheer-gowrigari

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

moritzjacobs avatar Sep 20 '18 08:09 moritzjacobs

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 avatar Jan 09 '19 18:01 protoEvangelion

@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 avatar Jan 30 '19 14:01 damienroche

@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

jonjohnjohnson avatar Jan 31 '19 05:01 jonjohnjohnson

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. 🤔

OliverJAsh avatar Feb 15 '19 10:02 OliverJAsh

Gecko implements overflow: -moz-hidden-unscrollable which is effectively overflow: clip. Don't know the background on why it's not unprefixed.

emilio avatar Feb 15 '19 11:02 emilio

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?

Baedda avatar Feb 19 '19 13:02 Baedda

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.

joma74 avatar Feb 19 '19 17:02 joma74

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

WangXBruc avatar Apr 25 '19 06:04 WangXBruc

@WangXBruc Unfortunately not. 🙁

valtlai avatar Apr 25 '19 06:04 valtlai

@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 avatar Apr 25 '19 23:04 jonjohnjohnson

@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 avatar May 01 '19 20:05 joshjg

@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.

JacobDB avatar May 01 '19 20:05 JacobDB

@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.

jonjohnjohnson avatar May 02 '19 00:05 jonjohnjohnson

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).

BenMorel avatar Sep 20 '19 17:09 BenMorel