electerious / basicScroll

Standalone parallax scrolling for mobile and desktop with CSS variables.
https://basicscroll.electerious.com
MIT License
3.63k stars 148 forks source link

jitters/jank when shrinking elements #39

Closed JiveDig closed 5 years ago

JiveDig commented 5 years ago

I'm not sure if this has to do with how I'm using the CSS vars, but if I scroll really slow, mostly back up to the top after shrinking the logo, I see the variables keep adjusting up and down. The header is using position: sticky; so the shrinking of the header shouldn't be adjusting the scroll position of the body. I've been trying everything I can to stop it or see what's causing it, but I'm not sure. Any ideas?

EDIT: I tested with the header using position: fixed; and it doesn't seem to do this.

EDIT 2: Logging scrollTop in the inside callback while the jitters are happening (and not scrolling manually, hand are off keyboard/mouse) shows it toggling 1px back and forth.

EDIT 3: It doesn't happen if I remove the margin scaling, and it still happens if I use padding instead of margin.

EDIT 4: I think it has to do with px rounding https://johnresig.com/blog/sub-pixel-problems-in-css/

This is Mac/Chrome.

screen recording 2019-02-25 at 04 30 pm

screen recording 2019-02-25 at 04 29 pm

It happens in this codepen for me as well: https://codepen.io/JiveDig/pen/rRNmwz

JiveDig commented 5 years ago

I think the issue is with px rounding. I wonder if there should be a setting (per prop?) to determine the amount of decimal places that it should round. I get the reasoning this change was made, but for times where we want px values I think we would benefit from only having 0 (maybe 1 or 2) decimal places. That would allow fine-tuned control for transforms, but more usable values for px values like padding/margin, and will hopefully alleviate issues like we see above.

JiveDig commented 5 years ago

Update: It's not px rounding.

I forced whole numbers in my props with this:

'--logo-width': {
    from: '1800000px',
    to: '1200000px'
},
'--logo-margin': {
    from: '240000px',
    to: '40000px'
},

and brought them down to the values I need like this:

max-width: calc( var(--logo-width) / 10000 );
margin-top: calc( var(--logo-margin) / 10000 );

and I still have the issue.

It's gotta be an issue when the height is adjusted on position: sticky; elements.

electerious commented 5 years ago

It's like applying a width transition using :hover. The width effects the layout and the cursor might now appear outside the element, changing the width back to the original.

You could try to track an element that has the same position as the header (and is visually hidden), but without adjusting the height. Then use direct to apply the variables to the real header: https://github.com/electerious/basicScroll#direct-mode

JiveDig commented 5 years ago

The code is tracking the body though, it's not tracking the header.

bodyScroll = basicScroll.create({
    elem: document.querySelector( 'body' ),
    from: 'top-top',
    to: '200',
electerious commented 5 years ago

You're right. I've missed the CodePen link.

I don't know what's going on here. Guess I need to take a deeper look at it by time. The code and tracking looks good and shouldn't cause any problems.

JiveDig commented 5 years ago

I ended up seeing the same thing, doing this same shrinking thing in Scrollmagic, so it’s either a browser bug or similar.

I think the developer world in general would benefit from the root of the issue being found, but unfortunately I’m out of ideas. I tried everything I could think of and always hit the issue.

An important find is that the issue is gone if you use position: fixed; it only happens with position: sticky;

Anyway, if you aren’t interested in digging, I understand if you want to close this. I’m pretty sure it’s not a basicScroll issue. I’m just hoping you can see something I missed.

👍🏼

electerious commented 5 years ago

It doesn't have much priority, but I would definitely like to take a look at it. Thanks for the report and information! The issue can stay open :)

electerious commented 5 years ago

I did some testing and it's indeed like I've assumed in my first answer. The header is using position: sticky which affects the height of the site, which changes the current scroll-position slightly, which changes the header height, and so on…

It doesn't matter which element you're tracking at the point because basicScroll uses the height of your scrolling container (usually the body) to determine the current scroll position/progress. That's why changing the height will confuse it.

I hope that helps 😊 Thanks for the report and suggestions!

JiveDig commented 5 years ago

Thanks for looking into it! Can you think of any other workarounds besides not using position:sticky;?

electerious commented 5 years ago

I don't think so. Here's the root of the issue: https://github.com/electerious/basicScroll/blob/master/src/scripts/main.js#L57

Changing the height will always change scrollTop. Working with absolutely positioned elements is the only way to get around this issue.