The CSS engine is an important part of web browsers and is usually very fast. However, using CSS incorrectly can negatively impact performance. In this section, we will explore some common issues related to CSS performance.

#How to measure CSS performance

You can measure CSS performance by using the performance panel in Chrome DevTools. It shows how long it takes to recalculate styles and how many items are affected by it. The blocks where the CSS engine is calculating styles are called Recalculate Styles and are shown in purple.

#Using Javascript instead of CSS

Writing CSS in JS files may provide a better developer experience, but it can negatively impact performance. When CSS execution depends on JavaScript or React execution, it introduces unnecessary cycles and bottlenecks for CSS. The JavaScript and React execution engine is single-threaded, and the CSS engine operates separately.

Write as much styles in CSS as possible

Do

Using CSS to take styling decisions.

/**
 * CSS only almost always beats runtime values
 * because it's decoupled from the react render cycles.
 */
export const SecondaryComponent = styled.div`
  margin-top: ${spacing[16]}
  &:last-child {
    margin-top: 0;
  }
`;

Don't

Using Javascript & Props to take styling decisions.

/**
 * Generating css based on a prop makes the styling dependent of the
 * React render cycle and hurts performance.
 */
const SecondaryComponent = styled.div<{ $marginTop: number }>`
  ${({ $marginTop }) =>
    $marginTop > 0
      ? css`
          margin-top: ${$marginTop}px;
        `
      : css`
          margin-top: 0px;
        `}
`;

#Using Abstractions in CSS

Abstractions are not inherently bad, but in CSS, they can negatively impact performance. Mixins, nested CSS, and improper use of abstractions can result in code that cannot be optimized by the framework. This can lead to a dependency on JavaScript or runtime instead of static code execution.

Rule of Thumb

  • Avoid mixins
  • Keep your CSS flat.
  • Prefer redundancy over abstraction.

Do

A bit of redundancy is better than abstraction. It improves performance, maintenance and readability.

/**
 * 👍 Even if the color and typography is "repeated"
 * It's better for performance, maintenance and readability.
 */
const MainComponent = styled.div`
  ${typography.base}
  color: ${compponent1Colors.TEXT};
  margin-top: ${spacing[8]};
`;

const SecondaryComponent = styled.div`
  ${typography.base}
  color: ${compponent1Colors.TEXT};
`;

Don't

Unneccessary abstraction, it's hard to read and maintain and worse for performance.

interface TextProps {
  $color: string;
  /*
  * 👎 Using props for styling is slower than CSS
  * and it makes the code more complex
  */
  $marginTop: MarginSize;
}

/* 👎 Creating trivial mixins and aplying them is expensive */
const textStyle = ({ $color, $marginTop }: TextProps) => css`
  color: ${$color};
  font-size: 16px;

  ${$marginTop &&
  /*
  * 🛑 $marginTop is an expensive runtime value
  * and nested css`` calls are always expensive
  */
  css`
    margin-top: ${$marginTop}px;
  `}
`;

/*
* 👎 Abstraction makes the code hard to read and slower
*/
const MainComponent = styled.div<TextProps>`
  ${textStyle}
`;

const SecondaryComponent = styled.div<TextProps>`
  ${textStyle}
`;

#Impact of Styled Components

Styled components dynamically adds CSS classes to the CSSOM (CSS Object Model) at runtime. React and styled components monitor when components become visible in javascript and add their corresponding styles to the CSSOM. If the styles are complex or there are many style classes involved, the browser has to perform a lot of additional work to handle them. This will again slow down the CSS engine.

Here is a comparison of the time it takes for React and Styled Components to apply styles. We use the performance profiler to record the same interaction and compare the duration of style recalculation. Notice that the time is significantly shorter in the "After" screenshot.

Don't

Styled Components manipulating the CSSOM

Recalculate Style with yak components

Do

Without CSSOM manipulation

Recalculate Style with yak components

The following code blocks styled components from changing the CSS classes in case you want to try this yourself.

CSSStyleSheet.prototype.insertRule = (...args) => {};
CSSStyleSheet.prototype.addRule = (...args) => {};
CSSStyleSheet.prototype.removeRule = (...args) => {};

#Avoid CSS selectors that are too expensive

Coming Soon