Controlling pointer-event induced paints while scrolling.

19 views
Skip to first unread message

Ruben Vreeken

unread,
Dec 10, 2014, 6:23:40 AM12/10/14
to enyo-dev...@googlegroups.com
I've been working a bit on scroll performance this past week and I've been toying around with techniques to reduce paint cycles due to hover events during scrolling etc.
After discussing the idea with Aaron Tam, he suggested I should share my findings here in the group as it might be interesting to discuss implementing something like this at a core level with some more fine-grain control.

So, on to the technique I'm currently using:

Basically, I've taken all :hover states out of my css, and replaced them with a hover class so the browser won't trigger hover-related paints by itself.  Then, I have created a simple mixin that uses mouseover and mouseout events to set a boolean hover property. If the hover property changes, I either add or remove the hover class. The result is the same visual hover effect as the :hover css state, but controlled entirely by javascript, rather than by the browser.

I've also created a scroller subkind that waterfalls the scrollStart and scrollStop events, so that contents of the scroller can detect when they're being scrolled. Using these events, the hover mixin can now selectively prevent adding/removing the hover class if it's inside a scrolling scroller. The result is no hover-induced repaints during scrolling, which makes for especially noticeable speedups on mobile devices.

The idea was inspired by some techniques I saw on the web where people disable pointer events inside active scrollers. The problem with the pointer-events technique, though, is that this also blocks clicks and taps etc. This is a problem for scrollers that simulate momentum and coast along after the users' drag interaction has finished. By only preventing visual hover effects while still allowing pointer-events, such interruptions in the users ability to interact with the controls inside the scroller are prevented.

I'd be interested to know what you all think about the general idea, how to improve it, if there's a place for this in enyo core, etc.

Pre101

unread,
Dec 11, 2014, 12:09:39 PM12/11/14
to enyo-dev...@googlegroups.com
That sounds pretty interesting.  What are the performance implications of moving to JavaScript based hover?  It would seem bubbling all those messages on mouse movement would have some fairly negative effects on performance.  Are you not seeing that?

Ruben Vreeken

unread,
Dec 12, 2014, 7:42:26 AM12/12/14
to enyo-dev...@googlegroups.com
I'm currently only making use of mouseover and mouseout events. These are fired by the browser itself and fire only on the relevant frames. So I don't have to evaluate any mousemove events to manage the hover styles.
If the bubbling does become an issue, an alternative might be to look at mouseenter and mouseleave. If I recall correctly, those fire only on the entered element and do not bubble.

I haven't ran any explicit performance tests on the impact of switching to JavaScript-based hovers, but in practice I have not experienced any slowdowns. So far, the test team has also not complained about slow hovers yet.




To give some background on the situation that drove met to build this. My problem case was a form with many hoverable elements inside a scroller. Scrolling the form was painfully slow.
Turned out, the thing that made it slow was that the browser decided to repaint the visible area of the scroller on every single frame. Especially mobile devices were not able to handle those paints fast enough.
The only way to get smooth scrolling was to get rid of the repaints.

I managed to get rid of scrolling-induced paints by applying a translate3d style to promote the form to its own gpu-accelerated layer. This was an improvement, but the hover effects would still trigger enough paints to slow things down.
While only one input would hover at a time the browser would repaint for the entire layer, rather than only the part of the layer that actually changes. Thus, the hover effects simply had to go if I ever wanted a smooth scroll.

If there is some way to move some markup into a separate gpu-accelerated layer while still letting the browser only repaint parts of that layer, that might be an alternative route to speeding things up. However, I don't know if that is possible.
Reply all
Reply to author
Forward
0 new messages