Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Should window.scrollTo() preserve visualViewport.offset{Left,Top}? #61

Closed
theres-waldo opened this issue May 8, 2019 · 7 comments
Closed

Comments

@theres-waldo
Copy link

This is less a question about the Visual Viewport API per se, and more about the underlying behaviour of the visual viewport itself, but it came up while investigating a Visual Viewport API web platform test so I thought I'd ask it here.

The test in question sets up a scenario where visualViewport.offsetLeft and offsetTop are nonzero, then performs window.scrollTo() (which has room to perform layout scrolling and does so), and then asserts that offsetLeft and offsetTop are unchanged.

The accompanying comment says:

// The visual viewport should be fully scrolled so even if
// scrollTo does normally "push" the layout viewport with the
// visual, there should be no change to either offsetValue

I'm not fully clear on the intended underlying conceptual model. Under what circumstances is window.scrollTo() expected to preserve the offset of the visual viewport relative to the layout viewport? (The comment suggests to me that it's not "always", though perhaps I'm misreading it.)

In the current Firefox implementation, window.scrollTo() sets both the layout and visual viewport offsets to the specified location (in other words, collapses the relative offset to zero). We chose this because we figured that a page performing window.scrollTo() may be trying to bring the user's attention to an element / section header etc. at the specified location, and so keeping that location out of view by preserving a potentially-large relative offset may be unexpected (kind of like how Element.scrollIntoView() should scroll an element into the visual viewport, which I note is a behaviour Chrome fixed recently).

Before considering a change to the Firefox behaviour, I'd like to understand the underlying conceptual model and the motivation for it better.

cc @bokand

@bokand
Copy link
Collaborator

bokand commented May 9, 2019

Making window.scrollTo affect only the layout viewport was intentional, see crbug.com/489206 for more details.

The basic problem is this: it's quite common on the web to use window.scrollX|Y in combination with Element.getBoundingClientRect. We saw a long tail of bugs of pages not working correctly when pinch-zoomed because the latter was relative to the layout viewport but window.scrollX|Y were (initially) visual-relative (e.g. popup menus on Facebook would be mispositioned). We decided to make the window APIs also layout-relative to solve these kinds of issues and make the platform consistent (and introduced visualViewport for cases that explicitly wanted it).

This was a bit of a scary/controversial change but IMHO it went smoother than expected. I expected it to fix more bugs than it introduced but I haven't seen any real bugs caused by it and, in retrospect, I think it was the right decision.

Regarding window.scrollTo, it'd be really strange/surprising if it didn't match scrollX|Y. I think Element.scrollIntoView is different because it's an explicit signal that the page wants to bring something into view; scrollTo is a bit more ambiguous.

@theres-waldo
Copy link
Author

To be clear, window.scrollX|Y already reports the layout viewport offset in Firefox (since Firefox 63), and window.scrollTo()'s primary effect is to move the layout viewport as well.

However, window.scrollTo() has to do something with the visual viewport offset as well -- it can't leave it alone in general, since it needs to obey the constraint that the visual viewport is contained within the layout viewport. (So, if the layout and visual viewport offsets are initially (0,0) (in absolute / page-relative terms), and you do window.scrollTo(1000, 1000), and the layout viewport size is (200, 200), the call can't leave the visual viewport offset at (0, 0)).

My question is, why is preserving the relative offset between the two viewports the right / intuitive behaviour, as opposed to a different choice, such as changing the visual viewport offset by the minimum possible amount to still obey the constraint, or collapsing the relative offset to zero (as Firefox currently does)?

@bokand
Copy link
Collaborator

bokand commented May 10, 2019

Ah, I see what you mean.

The short answer is this is probably a bias of our implementation that these viewports are effectively implemented as nested scrollers so you'd have to do extra work to not preserve the relative offset.

I think "minimum possible amount to still obey the constraint" would be bad UX because short scrolls that don't clamp the visual viewport wouldn't be seen at all which would be quite surprising. The visible effect of a scroll would depend on where the visual viewport started.

The "collapse to zero" choice seems reasonable. It has the advantage of always putting the user where the author intended the layout viewport to go (assuming they're scrolling the target to the top-left though and not, e.g., centering it).

OTOH, it could lead to annoying scenarios: imagine a user zooms in on a narrow column of text in the middle of the page. Any scrollTo now will reset the location off the column. Or if a page tries to lock the scroll offset by repeatedly calling scrollTo (I've seen this), the user can't zoom in and pan around.

But, TBH, I don't think we gave it a ton of thought. We just did the simple and unsurprising (to us) thing. The mental model here is that the visual viewport is just a magnifying glass taken the to user's screen; anything that happens on the screen shouldn't affect the magnifying glass. User can always zoom out and recenter if the page went to an unexpected place.

If there's compelling reasons we could consider changing it but it hasn't been an issue and it's worked quite well in my mind.

@theres-waldo
Copy link
Author

Thanks!

Do I understand correctly then that Chrome's behaviour is that window.scrollTo() preserves the relative offset in general? (I ask because the comment quoted in the issue description makes it sound like this may be conditional on something.)

@bokand
Copy link
Collaborator

bokand commented May 10, 2019 via email

@theres-waldo
Copy link
Author

Ok, thanks for clarifying!

I agree that this is a reasonable behaviour, and I will explore getting Firefox to do the same. Historically this has been a tricky area to fiddle with, but we can give it a try!

@theres-waldo
Copy link
Author

Forgot to close the loop here: the behaviour of preserving the relative offset has been implemented and shipping since Firefox 81, and we haven't noticed any compat issues from it.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants