Closed Bug 1259226 Opened 8 years ago Closed 8 years ago

Async scroll events resulting in laggy response in web content

Categories

(Core :: Panning and Zooming, defect)

47 Branch
defect
Not set
normal

Tracking

()

RESOLVED INCOMPLETE
Tracking Status
firefox47 --- wontfix
firefox48 --- wontfix

People

(Reporter: james, Unassigned)

Details

(Whiteboard: [gfx-noted])

Attachments

(2 files)

Attached video firefox-scroll.mp4
Calling document.elementsFromPoint() during a scroll event displays a visible delay.

Is this an asynchronous API? If so, that differs from the implementation in Chrome and results in the UI appearing to lag.

In IRCCloud we use this to display a clock and timestamp for the uppermost visible element at the currently scrolled viewport. When scrolling in Firefox, the clock update lags behind the scroll, and there's a delay before it shows or hides when moving off or returning to rest when fully scrolled down.

Attached are videos comparing Chrome and Firefox behaviour
Attached video chrome-scroll.mp4
This API was introduced by https://bugzilla.mozilla.org/show_bug.cgi?id=1164427
Which version of FF are you using? Nightly with e10s enabled, Aurora with e10s enabled or Release version of what?
And a minimal testcase would be great.
James, if you are seeing this on DevEdition or Nightly with e10s enabled (or more generally, if you go to about:support, and Asynchronous Pan/Zoom is enabled), it is most likely because the scroll event itself is async. This is a result of the async panning effort under way in Firefox at the moment - there is a blog post providing an overview of this at [1] - the section on "Scroll-linked effects" is the relevant section here.

[1] https://hacks.mozilla.org/2016/02/smoother-scrolling-in-firefox-46-with-apz/
And if that is the case, we need to consider to stop/abort scrolling when element(s)FromPoint is being used. Though, not sure what other APIs might have similar issues.
I wonder what Chrome does here.
...or we may keep scrolling, but need to tick refresh driver on child side at right time so that when
painting happens, scroll information is right.
Sorry, I must have removed the version info when editing this report. This was with Dev Edition 47.0a2 (2016-03-23).

And yes it does seem to be more a scroll issue, rather than elementsFromPoint. I'll update the title.
Summary: document.elementsFromPoint delay → Async scroll events producing UI lag
Here's a minimal test case that exasperates the delay by thrashing layout:
http://codepen.io/anon/pen/remJPe

If you increase the thrash amount, Chrome will eventually start dropping scroll frames, while in Firefox scrolling stays smooth, but the events get more and more delayed.

In my opinion it's desirable in this case for scroll frames to drop to keep the events in sync, as the issue is much less noticeable, especially at lower levels of layout thrashing, and the lag consistency makes more visual sense.

For our case, I'll see if we can do less on each event to prevent the desync, possibly using requestAnimationFrame, but this issue may always occur given changing conditions in the rest of the page, or on less powerful machines.
Moving to panning+zooming component, since that's where we put the other bugs that were of the same nature. Also removing dependency on bug 1164427 because it's not really specific to elementsFromPoint.

As all major browsers have already or are in the process of moving towards async scrolling, the best scenario here is to try to use effects that we can support on the compositor to do what you need. That won't always be possible, though. As our painting gets faster the issue will be less noticeable. We would very much prefer to keep our scrolling smooth rather than drop frames, although we are also building some machinery that will conditionally do the frame-dropping if we detect a scroll-linked effect on the page. It's not guaranteed to work perfectly though.
No longer depends on: 1164427
Whiteboard: [gfx-noted]
(In reply to Kartikaya Gupta (email:kats@mozilla.com) from comment #10)
> Moving to panning+zooming component

(Bugzilla must have eated that change or something. Making it.)
Component: DOM: Core & HTML → Panning and Zooming
Couldn't this affect be accomplished using sticky positioning and placing the timestamp element in-line with the scrollback? That would also avoid having to use elementsFromPoint, which is potentially expensive.

https://developers.google.com/web/updates/2012/08/Stick-your-landings-position-sticky-lands-in-WebKit

As well as all future browsers, you'll also find this problem on all current mobile browsers too.
uh, s/affect/effect/
No, positioning isn't the issue, the element being updated on scroll occupies a fixed position, it's the *contents* that update. That's not something any of the proposed CSS solutions in Kartikaya's blog post can address as far as I can tell. I'm curious to know if any other solutions are being considered for this.

I understand frame-dropping is something you're actively working to avoid, and I agree with the sentiment, but can you share any more about the conditional machinery you're building to drop frames when needed?

And fwiw, we're not targeting mobile browsers with our current web app, it would need significant rewriting to produce a good experience there. We have native apps that handle the majority mobile use case. But yes, we're aware that effects need to be approached differently on mobile.
(In reply to James Wheare from comment #14)
> No, positioning isn't the issue, the element being updated on scroll
> occupies a fixed position, it's the *contents* that update. That's not
> something any of the proposed CSS solutions in Kartikaya's blog post can
> address as far as I can tell. I'm curious to know if any other solutions are
> being considered for this.

Right, but I'm using IRCCloud now and there are already in-line time indicators with the same style and almost the exact same content as the fixed header that appears when scrolling. If those were made position: sticky, you could have an almost identical effect (it'd look a bit nicer as you'd have a smooth transition between time periods instead of just a sudden change and you'd lose the duplication of information) with much lower resource usage.

The only thing missing is the 'about X ago' information, which you could update via JS for the visible headers and the ones either side (information you could cache and update on scroll). It seems odd to commit to the exact effect you have now for the sake of it when it could perform and look better in every browser. Fair enough if there are Reasons™, but I'd consider re-working the effect before making your scrolling potentially janky.
As I've said we're going to look into what we can do to prevent or reduce the desync, and if we can't do that sufficiently, we may well switch to a different effect.

I had intitially misunderstood which element you were referring to making sticky, but you're right that it's missing the dynamic information that is the primary purpose of that element. Thanks for the suggestions though, definitely something to look into.

But bear in mind this is just one effect, there are countless other ways to update dynamic content on scroll that aren't solvable with CSS. So this may be an early warning of an issue web developers start to face when async scrolling becomes the norm. Developers will need to respond of course, but browser provided transition mechanisms would go a long way to making it more tolerable.

For instance, providing a temporary method of reverting to the old behaviour, with a deliberate opt in and an explicit caveat that it will be removed in future would allow developers to not have their sites break, while educating them and giving them time to work on alternatives. It would be nice if all web developers used FF dev edition, but do the stats show that's a realistic assumption?
(In reply to James Wheare from comment #16)
> For instance, providing a temporary method of reverting to the old
> behaviour, with a deliberate opt in and an explicit caveat that it will be
> removed in future would allow developers to not have their sites break,
> while educating them and giving them time to work on alternatives.

This is an interesting idea. What kind of time frame do you think would be appropriate for this?

I'd also like to mention that Safari has already switched to making scroll events async for the root scroll frame. This doesn't affect IRCCloud because you're using a nested scrollable frame, and Safari doesn't have async scrolling for those yet.
I'm not completely sure what behavior Edge has, but I suspect it's similar to Safari's.

Also, as an IRCCloud user myself, I must say that I vastly prefer using IRCCloud with async scrolling enabled over using it with sync scrolling. With sync scrolling, IRCCloud scrolls really sluggishly in Firefox, and having the displayed time in the header slightly lag behind is a much more pleasant experience than sluggish scrolling.

(In reply to James Wheare from comment #9)
> For our case, I'll see if we can do less on each event to prevent the
> desync, possibly using requestAnimationFrame, but this issue may always
> occur given changing conditions in the rest of the page, or on less powerful
> machines.

I have some ideas on this which I'll write into bug 1245455. Reducing the main thread work here will both improve sync scrolling performance and reduce the lag in the async case.
(In reply to James Wheare from comment #14)
> No, positioning isn't the issue, the element being updated on scroll
> occupies a fixed position, it's the *contents* that update. That's not
> something any of the proposed CSS solutions in Kartikaya's blog post can
> address as far as I can tell. I'm curious to know if any other solutions are
> being considered for this.

It's true that not all of the existing use cases have CSS solutions yet. If your use case cannot be described by one of the existing use cases in [1] then it's a novel use case and you should probably mention it on the dev-houdini mailing list so that we can take it into account as we move forward with creating new APIs and CSS properties to enable async-friendly scroll effects.

> I understand frame-dropping is something you're actively working to avoid,
> and I agree with the sentiment, but can you share any more about the
> conditional machinery you're building to drop frames when needed?

We have a bit of code that tries to detect when a page is using scroll-linked effects. The detection is very simple: if the page updates a positioning CSS property (e.g left, top, transform - see list at [2]) during a scroll event handler, we consider that page to be using scroll-linked effects. In particular, if they do it from a setTimeout or requestAnimationFrame we do NOT detect that page as using a scroll-linked effect. Currently we already display a warning in the web console when we detect this (based on the video you posted I suspect your page should also be getting this warning).

The machinery to "drop frames" simply turns off async scrolling when such a page is detected. It's an "all or nothing" deal, so if your page uses scroll-linked effects and the machinery is enabled, your page gets the old janky scrolling behaviour instead of async scroll events. We're not yet sure if we will be enabling the machinery at all, because it doesn't actually solve the underlying problem, it just hides it.

If we were to enable it, web authors wouldn't get any feedback (beyond the console warning, which I'm sure is widely ignored) that their pages are getting a subpar experience, and it does nothing to encourage authors to move towards CSS alternatives. Leaving the machinery disabled on Nightly and DevEdition is one possibility but unlikely to happen in practice because it means on Beta and Release we would be shipping "untested" codepaths to users which comes with a lot of risk.

At the moment this machinery is more of a "backup plan" and I wouldn't rely on it being enabled, at least not more than a couple of releases. Data we've collected shows that around 4% of desktop pages (3% on mobile) have some sort of scroll-linked effect [3] but in many cases the lag from the async scroll event is not really user-perceptible. I don't know if that's enough to warrant enabling the machinery, somebody in the product management team will probably make that call.

[1] https://github.com/RByers/css-houdini-drafts/blob/master/css-scroll-api/UseCases.md
[2] http://mxr.mozilla.org/mozilla-central/source/layout/style/nsDOMCSSDeclaration.cpp?rev=1a805ad24ef5&mark=82-92#81
[3] http://mzl.la/22HXo9q
For the record, the machinery I described above is in Nightly now, and can be enabled by going to about:config and setting the apz.disable_for_scroll_linked_effects pref to true. As I mentioned before, this is a backup plan and we have not yet decided if it will be enabled for release or not.
Summary: Async scroll events producing UI lag → Async scroll events resulting in laggy response in web content
I don't think there's anything we can do in this bug, not sure there's much point in leaving it open. Bug 1246290 added the apz.disable_for_scroll_linked_effects pref, and bug 1266874 is on file for turning it on for some segment of the population at some point.
Status: NEW → RESOLVED
Closed: 8 years ago
Resolution: --- → INCOMPLETE
You need to log in before you can comment on or make changes to this bug.

Attachment

General

Creator:
Created:
Updated:
Size: