position: sticky combined with height adjustment causes visual glitches (bouncing)
Reported by
reason.k...@gmail.com,
Jun 19 2017
|
||||||
Issue descriptionUserAgent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/59.0.3071.104 Safari/537.36 Steps to reproduce the problem: View this codepen: https://codepen.io/bluefantail/pen/zzKNpR Scroll to the bottom of the container. What is the expected behavior? The header sticks to the top of the screen and becomes smaller. What went wrong? The above happens, but the header glitches, bouncing 1px up and down - presumably because when the stuck class is added, the whole page gets smaller, and a fraction of a second later, the navigation is no longer stuck. Did this work before? No Does this work in other browsers? No To quote the StackOverflow question: In Safari, the scroll position is 'pushed back' to a state where it wont bug out. Then in Firefox, it does both of these, glitching for a second or two, before forcing the scroll position back up again. Chrome version: 59.0.3071.104 Channel: stable OS Version: OS X 10.12.5 Flash Version: From https://stackoverflow.com/questions/44567125/position-sticky-scroll-bouncing-when-combined-with-javascript-height-adjustme/44573447
,
Jun 19 2017
,
Jun 19 2017
Able to reproduce the issue on latest Chrome stable i.e., 59.0.3071.104, Beta 60.0.3112.32 , Dev 61.0.3128.0 and Canary 61.0.3135.0 on Windows 7,10, Mac and Linux. Note : This is also reproduciable on older chrome versions as well 57.0.2987.133 and 58.0.3029.110.
,
Jun 19 2017
,
Jun 19 2017
I don't think we should be bouncing between positions, and it turns out a patch I have in progress for issue 704817 fixes this instability. However, the expected behavior can't work. When the element gets the stuck class and begins shrinking the scroll length of the page decreases scrolling the frame up because you're scrolled to the bottom of it. As it scrolls up, it scrolls above the sticking point of the sticky element which triggers removing the stuck class. The element begins to grow again. I would expect at best that we end up pushing the scroll to just before the point where the element sticks. For the intended effect I imagine you only want to change the sticky element if the page is long enough for it to still be stuck after the change.
,
Jun 20 2017
This looks like a scroll anchoring bug, the relayout I described in #5 triggers scroll anchoring which then adjusts the scroll back down which cases the sticky element to become stuck again. I'm guessing we shouldn't anchor during a relayout due to an animation.
,
Jun 21 2017
Based on this thinking I put together a couple more examples implementing a check for page length, one that is too short, and one long enough to trigger the stuck class. This has improved the whole experience in Firefox and Safari, but in chrome there was still some jumping. However after turning scroll anchoring off in the browser, it behaves correctly, exactly as you've just suggested. Two examples for reference: Long page - https://codepen.io/bluefantail/pen/ZyKVvB Short page - https://codepen.io/bluefantail/pen/VWpgpw
,
Jun 21 2017
If you can reserve the space for the larger size of the sticky element so that the scrolling length doesn't decrease in the animation you can avoid needing to check the length as well. e.g. <div style="position:sticky; top:0; height:100px;"><header><!-- animates from height 100 down to 50 when stuck.--></header></div>. But yes, it sounds like scroll anchoring is causing some jumping with these layout inducing animations.
,
Jun 22 2017
Scroll anchoring is behaving as intended here. The scroll event handler changes padding on the sticky element, which affects its height, which shifts the <article> that we've anchored to, causing a scroll adjustment. The handler reacts to the adjustment causing a feedback loop. The animation is irrelevant. The fix is to avoid the content shift at the threshold, for example by putting the sticky element in a fixed height wrapper. Or you can disable scroll anchoring with "overflow-anchor: none".
,
Jul 10
I can confirm this is a problem after attempting the same thing. I'm using position sticky on my header and adding a class at the same time via JS (to trigger some animations which change height as the CodePen's above describe)
```
var header = document.getElementById("header");
var sticky = header.offsetTop;
window.onscroll = function () {
if (window.scrollY > sticky) {
header.classList.add("stuck");
} else {
header.classList.remove("stuck");
}
};
```
The height change does in fact mess with the window height and as it becomes 1px smaller will trigger the else which removes my animation. Removing the animation changes the height back to the original size and the loop starts again.
I'd like to see what we should do to code this correctly or if it is in fact a bug.
|
||||||
►
Sign in to add a comment |
||||||
Comment 1 by reason.k...@gmail.com
, Jun 19 2017