Re: ?scroll-block-on; avoiding user having to set chrome flags to get non-threaded scrolling?

277 views
Skip to first unread message

Rick Byers

unread,
Jun 28, 2017, 9:50:08 AM6/28/17
to Brad Lyon, input-dev
+input-dev, the team that owns this

Hi Brad.  There is currently no way to force touch scrolling to happen synchronously in any modern browser as far as I know.  It's still just too difficult to make such scrolling perform adequately.  However there's a lot of different features being worked on to help compensate for the problems this causes. Can you describe the use case you're trying to solve?

Thanks,
   Rick

On Tue, Jun 27, 2017 at 8:00 PM, Brad Lyon <brad...@gmail.com> wrote:
I saw that a year or so ago you had investigated adding a css property
that (I think) would allow forcing scrolling to block so that the page
could keep things in alignment based on whatever scrolling was
occurring.  This might be in the current chrome but require running
chrome in experimental mode.

I also know that you can force chrome not to use threaded scrolling
via a flag, but I am looking for a way that does not require the user
to do anything.

I'm writing in case you know how to do this.  I've heard something
about adding touchstart listeners, but this hasn't seen to work for me
so far.

Thanks for any info!

-Brad

Brad Lyon

unread,
Jun 28, 2017, 11:08:37 AM6/28/17
to Rick Byers, input-dev
thanks for responding!

I am not actually interested in touch scrolling (I saw that someone
said that simply adding a listener for that might effectively disable
threaded scrolling, which is why I mentioned it and this might be
confusing the issue).

I am interested in being able to keep two things synchronized on the
page after one of them scrolls: e.g., after div1 scrolls left, one
sets div2.scrollLeft=div1.scrollLeft. If I disable threaded
scrolling, that works, but it obviously forces the user to set the
flag. If threaded scrolling is used (the default), it is my
understanding that the scroll events are not sent fast enough - and
that simple approach of trying to keep the scrollLeft in sync results
in visible lag.


This example (http://tdresser.github.io/sync-scroll-offset-test/) and
your example at http://rbyers.github.io/scroll-blocks-on.html both
display the lag I am trying to avoid: if threaded scrolling is
enabled, you can see the little lag happen (actually whether or not
you have js do busy stuff in your example).

My case is actually a table where a few left columns are fixed and the
header is fixed. This is made of up several divs whose various scroll
properties need to be kept in sync. The little visible lag is very
noticeable when threaded scrolling is being used.

I am wondering if the solution is to have an overlay div that catches
scroll events and then updates the divs underneath it - at least that
way all of the syncs would occur at the same time, but it would of
course be a little more complicated.


Note: datatables has a fixed column feature that somehow avoids this
(I am trying to figure out how):
https://datatables.net/extensions/fixedcolumns/examples/initialisation/left_right_columns.html

Also, ember-tables has fairly good lock-step scrolling (they're using
a ton of divs to mimic a table):
http://opensource.addepar.com/ember-table/#/overview
--
B.F. Lyon, Ph.D.
http://bit.ly/bflyon-viz-summary

Brad Lyon

unread,
Jun 28, 2017, 12:06:23 PM6/28/17
to Rick Byers, input-dev
btw - here is where I saw the note about possibly forcing scrolling to
block (from Aug 2016,
https://github.com/bvaughn/react-virtualized/issues/369, "ScrollSync
doesn't seem to sync correctly/fast enough"):

"FWIW you can force the browser to block scrolling on the UI thread by
adding a touch event listener (as well as a few other ways) which will
keep both grids in lock-step but may negatively impact performance if
your cells take a long time to render...."

Again, I don't care about touch - it only came up because they are
suggesting that simply adding the touch listener might be a way to
force more synchronized updates. although I haven't gotten it to work
yet.

Brad Lyon

unread,
Jun 28, 2017, 3:05:23 PM6/28/17
to Rick Byers, input-dev
also btw - I am using trackpad on mac to see the lag stuff with
threading enabled. Mousewheel has lag as well. Using the scrollbars
directly doesn't seem to have a problem.

Majid Valipour

unread,
Jun 28, 2017, 11:28:39 PM6/28/17
to Brad Lyon, Rick Byers, input-dev
Hi Brad,

Using a touch event handler (e.g., touchstart handler) only blocks the start
of scroll but once the event is not prevented then we usually scroll
asynchronously (some more background on this particular behavior). 
Also it works for touch scrolls so for example  wheel scrolling will still
occur async. So it does not really achieve what you intended it to.

As Rick pointed out, we work hard to make all scrolling to happen async. There
are still situations [1] where that is not possible but we consider these bugs
and hope to eventually fix them. So I don't suggest relying on those long term
because our work will break such hacks in the future. Also different browsers
will have a different set of these so finding a workaround that works across all
browsers will be tricky, unreliable, and potentially hard to maintain.

> I am wondering if the solution is to have an overlay div that catches
scroll events and then updates the divs underneath it - at least that
way all of the syncs would occur at the same time, but it would of
course be a little more complicated.

This is probably the most reliable workaround at the moment. Note that this
probably mean that your scrollbars will move slightly out of sync with your
content. Also your scrolling will be subject to main thread jank. Having 
scrollers slightly out of sync as opposed to them being subject to main
thread jank is the trade off here.
 
> Also, ember-tables has fairly good lock-step scrolling (they're using
a ton of divs to mimic a table):

I am not sure if they are doing any lock step scrolling! It seems to be just a
single scroller which lazy loads its content. So maybe there is a solution
that does not need multiple scrollers to be in sync!

We are also working on a new AnimationWorklet API that can potentially help
your usecase.  This effectively allows one to tie an animations to a scroll
offset. You cannot exactly do  "div2.scrollLeft=div1.scrollLeft" but you can
make the above  workaround of an overlay div (except using a transform instead
of actual scrolls) to work off main thread to avoid the main thread jank.
Unfortunately this is still in development phase and not available yet. :(


Thanks,
Majid


[1] I don't think we have a documentation for exactly what these cases are but
here is a list in chromium source code. For example you can trigger the 
kHasClipRelatedProperty case and cause a scroller
to not get composited in chrome by having a clip on its content (e.g., clip-path: inset(0px
0px). Again I don't think this is the best idea. :)

Brad Lyon

unread,
Jun 29, 2017, 2:31:21 PM6/29/17
to Majid Valipour, Rick Byers, input-dev
Wow thanks for the detailed response. This is fascinating. Looking
forward to the AnimationWorklet thing.

Yes, there might be more involved solutions, and long-term this needs
to be done because - as you say - you folks are working hard to
*reduce* the cases where scrolling gets kicked back to the main
thread!

In a search for kHasClipRelatedProperty in the chromium issues list, I
didn't see any pending issues related to this atm.

Thanks again!

Rick Byers

unread,
Jul 10, 2017, 12:28:39 PM7/10/17
to Brad Lyon, Majid Valipour, input-dev, Nolan Lawson
BTW, forgot to mention earlier, the best overall discussion of this space is probably the blog from Nolan (Edge team).
Reply all
Reply to author
Forward
0 new messages