chrome dev tools profiling css variables

654 views Asked by At

I am new to profiling with chrome dev tools. I want to find out if/how much of a perf hit css variables are, so want to compare the same page with server side preprocessed css vs css variables.

In the chrome dev tools profiler I see activities like parse stylesheet, paint, etc. Any advice on which profiler activities to focus on when comparing preprocessed css to css variables?

2

There are 2 answers

0
inwerpsel On

General performance

CSS variables... are not really variables, but custom properties. You can use them like a variable using var(), but their mechanism is much better described as just another property that uses inheritance.

Hence, the considerations are largely the same as when you add or update normal properties. The initial rendering is not much affected by them, as they just result in a larger map size, something which rendering engines have been dealing with for a long time (sites with large amounts of CSS are quite common).

That said, it does allow to inflate these maps to arbitrary sizes which can be larger than the amount of normal properties that exist. I guess browsers also assume it's quite rare for a given element to specify every possible CSS property. So if you set hundreds or thousands of custom properties on an element, it's possible that some parts of the rendering pipeline are not optimal for these map sizes. I don't know a concrete example, but it feels like this should happen at least to some extent. In any case the impact should still be small.

1 "exception": using custom properties on the root element

If you're using the root element as a main dictionary to hold values in custom properties, AND you want to frequently update a value, you could run into a specific performance problem with a high impact and a possible optimization.

Say you have a deep tree, and your custom property --deep-element-color affects only a single element.

<html>
  <body>
    // a lot of elements here
    <div class="container">
      <ul>
        // more elements
        <li>
          <span class="deep-element">foo</span> <-- only this really changes
        </li>
      </ul>
    </div>
    // a lot more elements
  </body>
</html>
:root {
  // other custom props
  --deep-element-color: green;
}
// large amount of other rules
.deep-element {
  color: var(--deep-element-color);
}

If you change --deep-element-color by updating the root element stylemap, you would trigger a full style recalculation of all elements on the page, because the browser can't really tell where it's needed (in theory it can, but it doesn't). It just sees that the stylemap of the root element was updated, and will trigger a recalculation on all elements to propagate the inheritable properties.

The time this takes quickly gets on the order of multiple tens of milliseconds, and gets worse with total DOM size. You can see this on "Elements Affected".

example full recalculation

If, on the other hand, you update the value by setting the property on a granular selector, like this

.deep-element {
  --deep-element-color: blue;
}

you would only trigger a style recalculation on the deep elements, and nothing else, with the same visual end result. The time it takes is on the order of a few milliseconds, and doesn't scale with DOM size. This can be the difference that makes a color picker behave smoothly.

0
Garbee On

Style Calculation is the thing you're looking for. However, variables have little noticeable impact on performance. It would essentially be a map lookup internally which is extremely quick.