permalink

16

DevTools: Visually Re-engineering CSS For Faster Paint Times

Increasingly, whether it’s on desktop or mobile, users want their web experience to be snappy and delightful. This means that even if the browser is busy rendering the page or loading in content, the user should still be able to scroll around and interact with it.

Animations need to be silky, scrolling must be buttery-smooth and your page needs to contain little to no jank. This comes down to offering an experience that can run at 60 frames per second even on regular pages, not just games and animations.

To hit 60fps, we sometimes need to go beyond JavaScript as the sole performance bottleneck for our pages and spend more time investigating paint and layout issues – styles might actually be the core cause of our sluggish performance. In this post, I’m going to talk about optimizing paint times for your pages.

Diagnosing slow paint times

Before we begin, let’s quickly recall what a paint is. In a browser's paint phase, the render tree (a tree of visual elements in the order in which they will be displayed) is traversed and a "paint" method called to display content to the screen. Painting can either be global (against the whole tree) or incremental (partial). The basic flow of a rendering engine can be seen below, taken from Tali Garsiel’s “How Browsers Work”.

 

 

Last year, Ilya Grigorik and the Jank Busters team at Google shared two pieces of advice to help us understand how to diagnose slow paint times in our sites and apps.

To discover what styles are slow, it was suggested we:

  • Navigate to our page and open up the Chrome DevTools
  • Take a Timeline recording, noting the paint times
  • Inspect individual elements – starting with the larger ones we’re suspicious might be slow
  • Disable the styles for the element. You can remove an individual CSS style or a single style modification (if style is being set via your JavaScript)
  • Repeat this process, checking if your paint times have gone down. If they have, you've found the culprit and styles can start to be added back.
    • Alternatively you might want to play around with getting back the same visual style with different rules.

To establish what elements are slow, we used a similar process only rather than disabling styles, we set those parts of the DOM to display:none.

This process works fairly well, but we thankfully have some additional tooling we can use to help diagnose both paints and repaints.

What is a repaint?

During a user’s interaction with a page, only parts of it will be changed. For example, they may perform an action changing visibility or adding an outline to an element. The actual process of updating the screen is known as a repaint. Changes to your page (e.g JavaScript has modified CSS styles) invalidate the rectangle you see on the screen and cause your browser to view it as "damaged" (this is known as a damage rect).

A repaint is an expensive operation performance wise and can make your page look sluggish, which you ideally want to avoid. In WebKit, we keep an eye on what in the screen needs to be changed, creating a damage rectangle with the coordinates to parts of the page requiring repainting.

We save the old rectangle, prior to your changes, as a bitmap and then only paint the delta between the new rectangle and the old one. If you notice that there are particular areas of a page that require a lot of repainting, it’s useful to investigate what can be done to reduce the painting cost.

Reducing repaints – an updated Timeline workflow

Before we explore an updated workflow for reducing repaints and jank, let’s first look at a new shortcut that was introduced to help with this.

Pro-tip: we have a shortcut for quickly hiding DOM elements

We recently added helper to the DevTools (Canary) allowing you to easily toggle setting visibility:hidden on an element. When this style is applied to an element, it isn’t painted but does maintain the page layout in an unchanged state.

To use the shortcut, select a DOM element in the Elements panel and then press the H key. When paired with paint rectangles and the Timeline, you can easily evaluate which DOM elements are spending long on paint time.

Workflow

Let’s now look at what an expanded workflow for diagnosing paint and jank issues might look like:

  1. Open up your page, launch the DevTools and switch to the Timeline panel. Hit record and interact with your page the same way your user would.
  2. Check the Timeline for any frames that went over budget (i.e that are below that ideal 60fps). If you’re close to the budget, then you’re likely way over budget on mobile. Aim to complete all of your work within 10ms to have some margin. Note: This margin is for slower devices and you should almost certainly run this analysis on mobile using remote debugging (if building for mobile, which you should be!).  
  3. Once you’ve noticed you have a janky frame, check what the cause of it was. Was it a huge paint? CSS layout issue? JavaScript
  4. Fix the problem. If it was a paint or layout issue:
    1. Hide anything non-essential to your page. Inspect these elements in the Elements panel and then use the hide (H) shortcut to hide them
    2. Walk through the DOM tree, hiding different elements using the hide shortcut. You might discover hiding particular element(s) make a large difference to your frame rate.
    3. We now know there is something about an element slowing painting down. Uncheck styles that could have an impact on paint time (e.g box-shadow) for the element and check your frame rate again.
    4. Continue until you’ve located the style responsible for the slow-down.
  5. Rinse and repeat

Especially on sites that rely heavily on scroll, you might discover that your main content is relying on overflow:scroll. This is a real challenge as this scrolling isn’t GPU accelerated in any way so the content is repainted whenever your user scrolls. You can work around such issues using normal page scroll (overflow:visible) and position:fixed.

Additional Tools

Show paint rectangles

Under ‘Rendering’ in the Settings cog, you can enable a feature called ‘Show paint rectangles’ to help you visually see the area repainted in each frame. With this feature enabled, it can become easy to visualize what slows pages down. You want to keep the areas being repainted as small as possible.

 

FPS counter

An older, but equally as useful tool for visualizing frame rate and jank is the real-time FPS counter. This can be enabled in the DevTools by going to the Settings menu and checking Show FPS meter.

When activated, you will see a dark box in the top-right corner of your page with frame statistics. The counter can be used during live editing to diagnose what in your page is causing a drop-off in frame rate without having to switch back and forth with the Timeline view.

Keep in mind that just tracking the FPS counter may lead to you not noticing frames with intermittent jank. Be careful when using the content. It is also worth noting that FPS on desktop does not equal FPS on devices and special care should be taken to profile the performance there too.

Additional notes

  • Tools to force constant repainting are currently under works and should be available to all sometime soon. Keep an eye out on the Chromium blog for when this is available!
  • Some of the tooling recommended in this post works under the assumption that impl-side painting is not active in the version of Chrome you are using. This is currently not the case for Chrome beta for Android. Whilst we anticipate a solution to ensure tools continue to work with impl-side painting, it’s useful to keep this point in mind for the future.

Conclusions

Sometimes it’s the small, seemingly insignificant things that can be the greatest performance bottlenecks in your application. Watch your CSS and also keep in mind that it’s quite plausible to have poor paint times due to non-optimal JS, such as onscroll handlers firing multiple times or occupying a great deal of time.

Whilst I don’t suggest you purely focus on paint or layout, it is useful to be aware of the cost of using certain styles in the wrong way. I hope at least some of this comes in useful. Happy profiling!

16 Comments

  1. Pingback: DevTools: Visually Re-engineering CSS For Faster Paint Times | FWD: The Web

  2. Going to have to update my cheatsheet now with the shortcuts and stuff here :)

    I’ve actually been working on my portfolio site (+4 other projects) to “visually re-engineer” the parallax effect that you see when you click the nav links so that it is not so janky. There is some other areas for improvement but parallax sites have performance issues of course. So I’ve been building a canvas alternative which will be much better once I complete it all.

    Thanks to the different things in devtools, most which are mentioned here, I was able to determine what needed to be done differently so I know what I should focus on refactoring.

    Love the new stuff here too…

  3. Thanks for the post. I’ve been debugging fine, yet your tips help — esp with the overflow: scroll tip.

    Got one question, though. I noticed that your settings window resembles that of regular Chrome modals rather than the transparent black/yellow that I usually see when I hit up the settings section of Dev tools. Is it a theme? How did you do that?

    Thanks.

  4. The H = hidden trick is great, as is the FPS indicator. Unfortunately, I’m either too dense or these aren’t Developer Tools features in Chrome Version 24.0.1312.57 m, for Windows.
    Thanks for the tips, just the same. Very helpful and informative.

  5. Nice article, have seen a similar idea somewhere else, although I can’t help wondering whether the optimisations that are made in Google Chrome are going to be the same optimisations that would work for browsers that don’t use Webkit?

  6. Pingback: DevTools: Visually Re-engineering CSS For Faster Paint Times | Nuixen Technology

  7. Another useful post on improving page rendering, thanks Addy! I really like the new hide shortcut feature. One thing that would really be useful is if we could use Chrome Dev Tools to remotely debug the Android WebView. As far as I am aware remote debugging is only possible with a tool like Weinre. It would certainly speed up debugging in hybrid applications where (in general) I experience the most hank when compared to iOS.

  8. Pingback: Browser Repaint Performance | Bram.us

  9. Pingback: Jank Busting With Daft Punk

  10. Pingback: Video: Gone In 60fps – Making A Site Jank-Free

  11. Pingback: 10 Tougher Tasks to Reduce Page Weight | WarWebDev

Leave a Reply

Required fields are marked *.