[css-position-sticky] overconstrained sticky position interop issue with safari
Reported by
h...@jonjohnjohnson.com,
May 9 2018
|
||||||
Issue descriptionUserAgent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/68.0.3404.0 Safari/537.36 Steps to reproduce the problem: 1. Open testcase -> http://output.jsbin.com/qunekib/3 2. Scroll down, notice the "panel-by-panel" scrolling 3. Reach scroll position where panel #10 should scroll in and sit at bottom edge. 4. Panels #10 to #14 don't move/position according to bottom/top box offset values, like previous panels, they are the last 4, which is the amount of "nesting" used to show edges of panels with normal scrolling mechanism. These panels stick to top edge once reaching the scrolling end. 5. Open Safari and follow steps, noticing how top/bottom are respected all the way through. What is the expected behavior? When opposing box offsets do not conflict on a sticky positioned element, they should respect both offsets values. Like what is happening in Safari. What went wrong? Incorrect position of sticky elements when "perceived" conflicts in box offsets Did this work before? No Does this work in other browsers? Yes Chrome version: 68.0.3404.0 Channel: n/a OS Version: OS X 10.12.6 Flash Version: This also "works" in Firefox, though, rendering mid scroll flickers, even if they position elements correctly once scrolling concludes.
,
May 10 2018
I can also reproduce this. flackr@ do you know what might have caused this?
,
May 11 2018
As a side note, opposing box offsets have interop issues in general (not related to nesting) shown here... http://output.jsbin.com/zuwikov/ Left side shows blocks trying to stick to top and bottom. Right side shows normal flow position. View in chrome versus safari. There is somewhat of an issue filed with the csswg about implementation and interop versus spec language for conflicting box offsets. https://github.com/w3c/csswg-drafts/issues/1294
,
Jul 11
This is a very complex setup, I'm still trying to figure out how the 8 nested sticky elements are supposed to work together to produce the result and why the 10th one is different. You seem to have identified the underlying issue to be the resolution of conflicting box offsets which do not actually conflict, is it possible to make a simple test case of this issue?
,
Jul 12
This surely is a very complex setup, but when it becomes simpler, the conflicts disappear. As in, if the nesting of the "stack" of panels is not as deep, say 3 levels, then there is no conflict when offsetting the sticky positioning to reach the other end of the stack. I'll try to create a video showing how to reason about the DOM and utility classes in the example, and create outlines for each of the sticky elements to more easily visualize the conflicting boundaries.
,
Jul 16
flackr@chromium.org I attached an altered testcase that highlights a bit more of what's going on faking the scrollers box with the nested sticking offsets. Also added red markers to show how the offsets move. It is easier to see the difference in behavior between safari and chrome when loaded up side by side seeing the marker movements, which traverse the dom right to left.
,
Jul 17
Thanks! This is very helpful. But the thing that it's pointed out to me is that on #10 and later, the 4th nested .page-offset has different styles for top and bottom which is causing the incorrect behavior, matched by: .scrollport--2 .page:nth-last-child(-n + 2) [class^="page-offset"], .scrollport--3 .page:nth-last-child(-n + 3) [class^="page-offset"], .scrollport--4 .page:nth-last-child(-n + 4) [class^="page-offset"], .scrollport--5 .page:nth-last-child(-n + 5) [class^="page-offset"], .scrollport--6 .page:nth-last-child(-n + 6) [class^="page-offset"], .scrollport--7 .page:nth-last-child(-n + 7) [class^="page-offset"], .scrollport--8 .page:nth-last-child(-n + 8) [class^="page-offset"] bottom is calc(((var(--depth) - var(--dive) - var(--endOffset, 0)) * var(--gap)) + (var(--depth) * var(--page)) - ((var(--depth) - var(--dive)) * var(--page))) .scrollport--2 .page:nth-last-child(-n + 2) [class^="page-offset"], .scrollport--3 .page:nth-last-child(-n + 3) [class^="page-offset"], .scrollport--4 .page:nth-last-child(-n + 4) [class^="page-offset"], .scrollport--5 .page:nth-last-child(-n + 5) [class^="page-offset"], .scrollport--6 .page:nth-last-child(-n + 6) [class^="page-offset"], .scrollport--7 .page:nth-last-child(-n + 7) [class^="page-offset"], .scrollport--8 .page:nth-last-child(-n + 8) [class^="page-offset"] top is calc(((var(--dive) - 1) * var(--page)) + (var(--gap) * var(--indexRev, 0))) If you change bottom to calc(((var(--depth) - var(--dive)) * var(--gap)) + (var(--depth) * var(--page)) - ((var(--depth) - var(--dive)) * var(--page))) and top to 0 which the simple rules on #9 and earlier, this works correctly. I'm guessing the fact that it matches this complex selector is somehow unique to chrome and not safari?
,
Jul 17
Hey flackr@chromium.org, your suggested fix/edits do in fact make both safari and chrome behave the same, but you lose the visuals of reaching the end of the "stack" that safari does in fact support. Load up the test case without your edits and see how you lose that scrollend/top stacking visual in both safari as well as chrome. This is the key factor.
,
Jul 17
At the 4th second in the video, the pages stack up at the top of the scrollbox? This is what both chrome and safari allow. But when chrome allows this top sticking for the last set of pages, it breaks the bottom sticking boundaries for each of those pages offsets for how they are positioned as they start to scroll in. http://cl.ly/szXQ If you load the test case up in chrome and safari, side by side, you can see the red line visuals differing behavior in the last 5 pages of the stack scroll into view.
,
Jul 17
Thanks for the explanation, this makes sense. I'll look into this tomorrow. I now know exactly which element has gotten the wrong position, so it should be easy to debug exactly why it's gotten the incorrect sticky offset and hopefully get to the bottom of this issue. It seems wrong that the non-zero top offset would push that element down before it has even scrolled into view - let alone anywhere near the top of the viewport.
,
Jul 18
So the sticky offset of the particular container element in question (i.e. document.querySelector('.page:nth-child(10) .page-offset---') ) is initially 0, it is in fact getting its offset of 60px from the flex layout of its parent item.
I started focusing on this difference in layout and reduced the testcase to a pretty minimal example. I believe this to be a layout compat issue with flex + overconstrained sticky. Over to layout team to triage.
,
Jul 19
Sorry that my initial testcase is so complex, but from what I've seen, it's not related to display flex. Attached is a quick (and dirty) non-flex (spoofing the vertical centering that flex allowed with pseudo elements) version of my original testcase. It still has the issue, when reaching the 10th page (and last pages which have both top and bottom offsets not set to auto), of being positioned incorrectly when compared to safari. Check the testcase in both browsers and see the issue and that flex containers are not being used. Thanks for all your help flackr@chromium.org
,
Jul 19
Right, I thought through this use case some more and I'm pretty sure it comes down to the difference of Safari obeying the bottom constraint over the top, and Chrome and Firefox preferring the top over the bottom. See for example this case: http://output.jsbin.com/xigoges or http://jsbin.com/buzesud/edit?html,css,js,output Confusingly, we seemed to have recorded that Safari preferred the top on https://github.com/w3c/csswg-drafts/issues/1294 but this doesn't seem to be the case. I also don't observe this behaving correctly in firefox, even the original demo (http://output.jsbin.com/qunekib/3) seems to immediately stack at the top of the browser whereas Chrome and Safari stack at the bottom and when you reach the bottom the topmost visible card continues to slide up.
,
Jul 19
I mentioned that github issue in my first comment here. And within that issue, I commented further down the thread, recording each browsers differences when "overconstrained" edges (https://github.com/w3c/csswg-drafts/issues/1294#issuecomment-373514495). Safari uses both simultaneously, and averages the difference as you scroll through the conflicting in-flow position (see in safari -> http://output.jsbin.com/zuwikov/). But in this example, I don't think chrome us just preferring the top over bottom. From watching the scrolling within the second testcase I attached, you see the offset box visuals not being in conflict. See how that case doesn't show safari "averaging" the offsets during scroll. When I test all these testcases in Firefox, they behave like safari. They just drop frames and often need text highlighting of dom to cause a repaint, where the offsets show correctly. I do have firefox "WebRender" enabled which, I believe allows for the parity with safari (https://bugzilla.mozilla.org/show_bug.cgi?id=1456938#c1).
,
Jul 19
Just checked again and see that firefox 63.0a1 (2018-07-16) (64-bit) does in fact treat sticky positioning the same as safari. It just has poor rendering even when enabling webRender.
,
Jul 19
Re #17, apologies it was just due to my old version of firefox that I was seeing old behavior. If Firefox and Safari are aligned on splitting the conflict we can align on this behavior as well though I hope we can get this behavior written in the spec.
,
Jul 19
flackr@chromium.org again, thanks for all your time and insight. Though firefox and safari have parity for the original testcase(s), it doesn't actually "split the conflict" as you say. In my example from the github issue I referenced in #16, a simpler (non-nested and non-shared containing block) http://output.jsbin.com/zuwikov/ example. It highlights how firefox and chrome do not split the conflict. But again, the original testcase here doesn't actually have a box offset conflict to split. For some reason chrome thinks there is a conflict that isn't there?
,
Aug 3
flackr@chromium.org, here is a real example of opposite offsets conflicting: http://jsfiddle.net/78oamb6u/53/ In it, you can open it up and see how safari is the only browser that allows both to affect the position. Firefox uses top, as does chrome, but they handle margins a bit different when creating the height of the "scrollbox"? In my original nested sticky position example, both firefox and safari "sequentially" move the sticking boxes around, but again, that example doesn't seem to have conflicting box offset values, though something in chrome thinks the values conflict. |
||||||
►
Sign in to add a comment |
||||||
Comment 1 by krajshree@chromium.org
, May 10 2018