---
title: Can you paint with all the colors of the wind?
teaser: Identify unnecessary rendering and improve your app's performance.
tags: css,tools
author: Stephen Lindberg
published_on: 2018-07-10
---

Modern CSS has some great features for making user interfaces more pleasing and
understandable. One of these features is transitions. Transitions are a quick
way of animating a CSS property whenever its value is changed. They are
available for several properties such as `transform` and `color`.

![repainting illustration](https://images.thoughtbot.com/blog-vellum-image-uploads/taaYAqwwR3CYgq9468EF_css-transition-illustration.jpg)

Transitions and animations can be effective for communicating actions and
contexts. They provide a visual narrative to help people understand how the
state of the user interface is changing, and on a larger scale they help build
continuity in the mental model the user has of your app's landscape.

On a recent project, I discovered that our CSS declared site-wide transition
rules for all `<a>` and `<button>` elements.

```css
a {
  transition: color 0.5s;
}

button {
  transition: background-color 0.5s;
}
```

In most cases this produces a desirable result. Small elements like text
links and buttons transition their text or background color when the cursor
hovers over them. This is more pleasing than simply changing the color
immediately.

### The cost of painting

During the transition, the browser is re-rendering the text dozens of times per
second using a slightly different color each time. Rendering elements in the
browser, or "painting", is a process that requires optimization to keep our apps
running quickly. If the browser repainted the entire screen every time a single
element changed, we would notice a significant drop in performance. Fortunately
for us, browsers are optimized to repaint only when necessary. However, there
are sometimes situations where the browser can't perfectly determine when to
paint and when not to paint.

Repainting a small element like text during a half-second transition is no big
deal, but what about larger elements? Performance impact is directly related to
the area of the screen the browser must repaint, and the calculations required
for painting. So what if the browser is repainting an element with lots of
complicated CSS calculations, nested elements, or large images?

```html
<a href="…">
  <img src="a-big-image.jpg">
  <div>
    Some other things
  </div>
</a>
```

The above HTML is an example of a pattern I came across in the same project.
Given what we know about the transitions on all `<a>` elements, what do we
expect to happen? The browser was repainting the entire element at every step of
the transition.

I discovered this while using the aptly-named [paint flashing][paint-flashing]
tool in Firefox (Chrome has an [equivalent tool][chrome-paint-rectangles]). Every
time an element is repainted, it also paints a semi-transparent,
randomly-colored rectangle over the element. This is handy for identifying
unnecessary or expensive paint calls (and having impromptu raves at your desk).

### Making an exception to the rule

Instead of revisiting our site-wide link transition rule (which works as
intended most of the time), we decided to create a utility class which we can
use to remove all transitions from an element:

```css
.u-no-transition {
  transition: none !important;
}
```

This is one of the very few cases in which we should use `!important` as part of
our rule, because some transition rules will likely have more specific selectors
than our utility class, and we want to override them.

Takeaway: keep an eye on browser performance using tools such as the profiler
and paint flashing tool to avoid unnecessary rendering. Rendering affects not
only performance, but also battery life.

[paint-flashing]: https://developer.mozilla.org/en-US/docs/Tools/Paint_Flashing_Tool
[chrome-paint-rectangles]: https://developer.chrome.com/devtools/docs/rendering-settings
