Rendering performance — How to improve it and lessons that we learned in Outplayed

Eyal Biran
Overwolf Blog
Published in
6 min readJul 19, 2020

There are many performance tools built-in Chromium out of the box, that could help you find and debug performance issues in your app. The key to success is using the right tool for the task, exactly like bringing the right gun for a fight.

When facing a performance issue in your app, the first thing to do is to determine which category to focus on. This will help you to decide which tools to use. In general, there are three main performance categories:

  1. Load: It takes too long since the app opens until content is loaded and intractable.
  2. Logic: It takes too long to respond to user actions, or an ongoing background task is slowing the app.
  3. Rendering: UI elements and animations seem sluggish and unresponsive.

In this article, we’ll focus on rendering issues, how to identify them, what tools to use, and a few tricks and tips to help you get started.

Does your app have rendering issues?

Detecting whether your app has rendering issues is done by exploring the app features. If you experience one of the following, then you probably have some rendering issues:

  • Mouse hover animations are slow and sluggish
  • Transition animations are slow and sluggish
  • Switching between different views, like windows or menus, takes too much time and seems bumpy
  • UI elements are not responsive

Most of these issues are caused due to improper layout and CSS usage that results in unneeded paints. For example, when we hover a button and get the hover effect, we obviously must paint that button again. But if we needlessly paint other areas in the UI, as a result of the button hover, we are wasting system resources.

When too many things paint and repaint, every time — we start to see noticeable performance degradation.

Tools

Fortunately for us, chrome has great tools to help us detect and solve rendering problems. Open Chrome DevTools, click on the three dots menu, “More tools”, and “Rendering”.

This will open the Rendering tab

Read more about the Rendering tab here: https://developers.google.com/web/tools/chrome-devtools/evaluate-performance/reference#rendering

Paint flashing

The main tool for painting issues is Paint flashing. It’s very straight forward, enables this option and you’ll see on top of your UI green rectangles indicating that the area has been repainted.

For example, below is Outplayed. When hovering over the video player, we show the player controls overlay.

Player not hovered — no player controls overlay.
Player hovered —show player controls overlay.

So we expect the rectangle of the entire video player to be repainted. But with Paint flashing enabled, hovering the player will show us this:

Hover player with unexpected repainted areas.

Well, that’s not good. Hovering the video player results in the repainting of many unrelated areas. Clearly we had an issue that needed to be fixed. Using some of the tricks presented below, we were able to fix the issue, and get the expected result:

Hover player with minimal repainted areas.

That’s more like it. And now, we continue to test our app, with the Paint flashing enabled, searching for all the cases we get unexpected green areas.

Read more about paint areas here: https://developers.google.com/web/fundamentals/performance/rendering/simplify-paint-complexity-and-reduce-paint-areas

Scrolling performance issues

We use scrolling whenever we want to offer more content than what fits the screen, but scroll will actually result in painting the entire scrolled area again, and again. That does not mean we should not use scrolls, but we do need to pay attention to scroll areas.

Enabling the Scrolling performance issues flag will mark on the app UI the areas that are going to be repainted when the user scrolls. It will also show any registration to scroll events, that helps us verify that things are as expected.

For example, in Outplayed, we would expect to see 2 scroll areas. One at the matches navigation at the top, and one at the timeline at the bottom.

2 scroll areas are expected.

Enabling the Scrolling performance issues flag had a surprising result:

Where did that “mousewheel event listener” come from?

So aside from being a good verification that everything is working as expected, we actually can find unexpected behaviors. Why do we have a mouse wheel event listener registered to the window? After fixing the issue, the areas are marked as expected:

Seems good. 2 scroll areas, as expected.

A reference for this flag can be found here: https://developers.google.com/web/tools/chrome-devtools/evaluate-performance/reference#scrolling-performance-issues

More tools

While we found the above tool to be the most useful when trying to improve render performance issues, the Rendering tab has many other tools to offer. You can read more about each of them here: https://developers.google.com/web/tools/chrome-devtools/evaluate-performance/reference#rendering

Tips and Tricks

So we were able to dramatically improve the rendering performance for Outplayed using the above tools. Here is a list of the things we ended up doing:

  • Use CSS “contain” whenever possible — The easiest way to remove those unrelated repaint areas, is to use the CSS property contain. This property allows you to indicate that an element, and it’s content, are independent and will not affect other areas. This will result in amazing performance benefits.
  • Avoid backdrop-filter — Although it’s supported, backdrop-filter has terrible performance and a huge negative impact on the overall performance of the rendering pipeline. If you must have filters, try to use regular filters when possible, and restrict backdrop-filter to small areas.
  • Reduce the use of z-index — Instead, try to place the elements in their respective locations in the DOM.
  • Remove unnecessary use of background-attachment: fix — From our experiments, background-attachment: fix has a negative impact on performance, and when possible it’s better to avoid it.
  • Handle mouse wheel event listener better — When registering an event listener, you can add extra parameters that may improve the overall performance. For example, adding the passive flag, helped us to fix the issue we had with the mouse wheel.
  • Remove use of mix-bland-mode — Although might be useful sometimes, mix-bland-mode will have a negative impact on performance.
  • Reduce selectors complexity — Using nested selectors will trigger unneeded recalculations. For example, when writing “#menu > .items > li > h1”. Modifying things inside “#menu” will trigger recalculations for it, but also for “.items”, “li”, and “h1” elements in that node. To avoid that, use a single css selector, like “.menu-title”.
  • Use css grid as base layout — Creating the base layout using css grid technique allows you to place components inside grid cells and isolate them more easily.

--

--