Investigate performance impact of many CSS variables

As our usage of design tokens expands, particularly within components like buttons, badges, and broadcast banners, we are increasingly populating the :root with numerous CSS custom properties. This issue aims to investigate the performance implications of maintaining a large number of CSS variables at the :root level.

The main questions raised include:

  • Performance Impact: What is the performance cost, if any, of having numerous CSS variables defined at the :root level? Optimization: Should we reduce redundancy in design tokens, particularly those with similar values but different names, or should we maintain descriptive names for clarity in different use cases?
  • Organization: How can we structure design tokens more efficiently? Should we continue to define every variation (e.g., button.type.background, button.type.border) or consolidate these into more generalized tokens?

Tasks

  1. Performance Benchmarking: Test the performance impact of having a large number of CSS variables defined in the :root. Compare the loading times, rendering times, and potential reflow/repaint issues with varying numbers of custom properties. Refer to existing studies like:
  2. Analysis of Current Design Tokens: Review the existing design tokens to identify redundancies, especially in cases where multiple tokens share the same value. Consider the pros and cons of reducing the number of tokens by using generalized names versus maintaining specific, descriptive names.
  3. Consideration of Future Design Needs: Evaluate how adding new themes (e.g., high contrast, dark modes) will further impact the number of custom properties.
  4. Recommendation Development: Provide recommendations on whether to continue adding custom properties to :root, explore alternative structuring methods, or reduce the total number of variables.
  5. Documentation: Document findings and best practices for managing CSS variables at scale. Outline a plan for possible refactoring of current design tokens to improve performance and maintainability.

Outcome

The goal of this investigation is to understand the performance implications of our current strategy for design tokens and provide actionable recommendations to optimize our use of CSS variables without sacrificing flexibility or maintainability.

Findings

I build the following project: https://gitlab.com/vanessaotto/css-variables-benchmark/-/tree/main?ref_type=heads

It created 4 different HTML files:

  • no-custom-properties.html
    • No custom properties created in :root, and no custom properties used in CSS Classes
  • custom-properties-single.html
    • Custom properties created in :root, but not used in CSS Classes
  • custom-properties-triple.html
    • 3 Levels of Custom properties created in :root, and the 3rd used in the CSS Classes
  • custom-properties-triple-third.html
    • 3 Levels of Custom properties created in :root, but only the 1st used in the CSS Classes

I documented the results in README.md file of the project. You can also find code examples about the differences in those 4 files there.

The TL;DR: and important information is: There is no significant performance impact when comparing "no custom properties" vs. "custom properties" as long as the HTML and CSS which has to be download has a comparable size. The difference was 1.8% higher (539ms vs. 549ms = 10ms difference in total rendering time) for these specific test cases.

We can see an increase of rendering time comparing "3 levels of custom properties" vs. "1 level of custom properties". This is expected though, as I tripled the <style> block length for this test. This is why I specifically checked if it has an impact on the CSS Rendering itself, or if only the loading time of having 10000 more LOC to load is the primary reason for the increase: There was no performance change. Means: It has no performance impact on the CSS Rendering color: var(--gl-text-color-subtle, var(--gl-color-neutral-600, #626168)) to --gl-text-color-subtle: --gl-text-color-subtle: var(--gl-color-neutral-600); to var(--gl-color-neutral-600): #626168;, but makes an difference in how much HTML/CSS has to be downloaded.. The overall time is ~14% higher for 3-level custom properties compared to 1-level custom properties. While 14% sounds like "a lot", we're comparing 549ms to 626ms. Although not being an expert in measuring performances, the numbers in this range and measured in milliseconds, does not sound like it would stop us from adding more and more design tokens now.

Edited by Dan MH