logoAnt Design

⌘ K
  • Design
  • Development
  • Components
  • Blog
  • Resources
5.25.0
  • 👀 Visual Regression Testing
  • Why is it so hard to disable the date?
  • HOC Aggregate FieldItem
  • Line Ellipsis Calculation
  • 📢 v4 surpassed maintenance period
  • Type Util
  • A build ghost
  • Ant Design meets CSS Variables
  • Historical Debt of API
  • Stacked Notification
  • Color Models and Color Picker
  • Extends Theme
  • Virtual Table is here!
  • Happy Work Theme
  • Where is the dynamic style?
  • Suspense breaks styles
  • Bundle Size Optimization
  • Hi, GitHub Actions
  • To be what you see
  • Pain of static methods
  • SSR Static style export
  • Dependency troubleshooting
  • Contributor development maintenance guide
  • Repost: How to submit a riddle
  • Tooltip align update
  • Unnecessary Rerender
  • How to Grow as a Collaborator
  • Funny Modal hook BUG
  • about antd test library migration
  • Tree's check conduction
  • Some change on getContainer
  • Component-level CSS-in-JS

Where is the dynamic style?

Resources

Ant Design X
Ant Design Charts
Ant Design Pro
Pro Components
Ant Design Mobile
Ant Design Mini
Ant Design Web3
Ant Design Landing-Landing Templates
Scaffolds-Scaffold Market
Umi-React Application Framework
dumi-Component doc generator
qiankun-Micro-Frontends Framework
Ant Motion-Motion Solution
China Mirror 🇨🇳

Community

Awesome Ant Design
Medium
Twitter
yuque logoAnt Design in YuQue
Ant Design in Zhihu
Experience Cloud Blog
seeconf logoSEE Conf-Experience Tech Conference

Help

GitHub
Change Log
FAQ
Bug Report
Issues
Discussions
StackOverflow
SegmentFault

Ant XTech logoMore Products

yuque logoYuQue-Document Collaboration Platform
AntV logoAntV-Data Visualization
Egg logoEgg-Enterprise Node.js Framework
Kitchen logoKitchen-Sketch Toolkit
Galacean logoGalacean-Interactive Graphics Solution
xtech logoAnt Financial Experience Tech
Theme Editor
Made with ❤ by
Ant Group and Ant Design Community
loading

As we all know, antd v5 uses CSS-in-JS to support the needs of mixed and dynamic styles. On the contrary, it needs to generate styles at runtime, which will cause some performance loss. Therefore, we developed the @ant-design/cssinjs library at the component library level to improve the cache efficiency through certain constraints, so as to achieve the purpose of performance optimization. But we don't stop there. We can skip the stage of generating styles at runtime through some logic.

Where is the dynamic style?

If you have checked the official website of Ant Design, you will find that Ant Design's components do not dynamically insert <style /> to control styles, but use CSS files to control styles:

  • button
  • style

document.head has some css file references:

  • umi.[hash].css
  • style-acss.[hash].css

The former is the style content generated by dumi, such as Demo block, search box style, etc. The latter is the style file generated by SSR. In the custom theme document, we mentioned that we can pre-bake the components used in the page through the overall export method, so as to generate css files for cache hit to improve the next open speed. This is also the way we use in the official website. So the components in the Demo actually reuse this part of the style.

Wait a minute! Isn't CSS-in-JS supposed to generate style hash at runtime and align it with <style />? Why can css files also be aligned? Don't worry, let's take a look.

CSS-in-JS Hydration

Application level CSS-in-JS solutions will calculate the hash value of the generated style and store it in the cache. When rerender, it will first check whether the corresponding style exists in the cache. If it exists, it will be used directly, otherwise it will be generated again. This can avoid repeated generation of styles, so as to improve performance.

CSS-in-JS process

Every dynamically inserted style is also identified by hash. If the <style /> with the hash already exists in the page, it means that inline style injection has been done in SSR. Then <style /> does not need to be created again.

You can find that although the <style /> node can be omitted, hash still deps on the calculated style content. So even if there is reusable style in the page, it still needs to be calculated once. It's really not cost-effective.

Component-level CSS-in-JS

In the component-level CSS-in-JS article, we mentioned that Ant Design's Cache mechanism does not need to calculate the complete style. For the component library, as long as the Token and ComponentName can determine the consistency of the generated style, so we can calculate the hash value in advance:

CSS-in-JS hash compute way

Therefore, we found that we can reuse this mechanism to realize whether the component style has been injected on the client side.

SSR HashMap

In @ant-design/cssinjs, Cache itself contains the style and hash information corresponding to each element. The previous extractStyle method only takes the content of style in Cache for packaging:

tsx
// e.g. Real world path is much more complex
{
"bAMbOo|Button": ["LItTlE", ":where(.bAMbOo).ant-btn { color: red }"],
"bAMbOo|Spin": ["liGHt", ":where(.bAMbOo).ant-spin { color: blue }"]
}

Get:

css
:where(.bAMbOo).ant-btn {
color: red;
}
:where(.bAMbOo).ant-spin {
color: blue;
}

We go further to reuse the style. We also extract the path and hash value:

tsx
{
"bAMbOo|Button": "LItTlE",
"bAMbOo|Spin": "liGHt"
}

And also pack into css style:

less
// Just example. Not real world code
.cssinjs-cache-path {
content: 'bAMbOo|Button:LItTlE;bAMbOo|Spin:liGHt';
}

In this way, the SSR side will retain all the information we need, and then we only need to extract it on the client side.

CSR HashMap

It's much simpler on the client side. We can extract the HashMap information through getComputedStyle:

tsx
// Just example. Not real world code
const measure = document.createElement('div');
measure.className = 'cssinjs-cache-path';
document.body.appendChild(measure);
// Now let's parse the `content`
const { content } = getComputedStyle(measure);

In the component rendering stage, useStyleRegister will first check whether the path exists in HashMap before calculating CSS Object. If it exists, it means that the data has been generated through the server. We only need to extract the style from the existing <style />:

tsx
// e.g. Real world path is much more complex
{
"bAMbOo|Button": ["LItTlE", "READ_FROM_INLINE_STYLE"],
"bAMbOo|Spin": ["liGHt", "READ_FROM_INLINE_STYLE"]
}

And for the style provided by CSS file (such as the usage of the official website), it will not be removed like <style />, we can directly mark it as from CSS file. Like inline style, they will be skipped in the useInsertionEffect stage.

tsx
// e.g. Real world path is much more complex
{
"bAMbOo|Button": ["LItTlE", "__FROM_CSS_FILE__"],
"bAMbOo|Spin": ["liGHt", "__FROM_CSS_FILE__"]
}

Summary

CSS-in-JS has been criticized for its runtime performance loss. In Ant Design, if your application uses SSR, you can skip the stage of generating styles at runtime on the client side to improve performance. Of course, we will continue to follow up the development of CSS-in-JS to bring you a better experience.