What is the
Css-in-js is a technique, not a library implementation. To put it simply csS-in-JS is to write the applied CSS styles in JavaScript files, rather than separate files such as.css,.scSS, or less, so that you can use JS elements in your CSS such as module declarations, variable definitions, Language features such as function calls and conditional judgments provide flexible and extensible style definitions. It is worth mentioning that ALTHOUGH CSS-in-JS is not a new technology, its popularity in China is not very high. It was originally introduced due to the popularity of some component-based Web frameworks such as React, Vue and Angular. It also makes developers want to encapsulate component CSS styles into components to solve a number of problems with native CSS writing. Css-in-js is the most popular in the React community because React doesn’t care how users style components, whereas Vue and Angular have their own styles framework.
This article will analyze the benefits and problems of CSS-In-JS to help you decide whether to use CSS-In-JS in your projects.
Different implementations
There are many libraries that implement CSS-in-JS, more than 61 by one count. Although each library solves the same problem, their implementations and syntax are quite different. There are two main implementations: Unique CSS selectors and Inline Styles (Unique Selector VS Inline Styles). Next, we will look at two representative implementations that correspond to these two implementations: Styled – Components and Radium.
Styled-components
Styled components is arguably the most popular library for CSS-In-JS, and github has a star rating of over 27K so far. Using Styled Components, you can use ES6’s Tagged Templates to define a set of CSS properties for the Component to be styled. When the Component’s JS code is parsed and executed, Styled – Components dynamically generates a CSS selector and inserts the corresponding CSS style into the head tag as a style tag. Dynamically generated CSS selectors have a small set of hash values to ensure global uniqueness and avoid style collisions.
Css-in-js Playground is a website for quickly experimenting with different CSS-in-JS implementations. Here is a simple example of implementing forms using styled components:
As can be seen from the above example, styled Components do not require you to set a style name for the DOM node that needs styling. After using the tag template string definition, you will get a Styled Component, which can be used directly in JSX. Next, let’s open DevTools and take a look at the generated CSS:
As shown in DevTools above, the Styled Component style exists within the style tag, and the selector name is a random hash string. This implements scoping styles for local CSS, and the styles of the components do not conflict. In addition to the Styled components, other implementations that use the sole CSS selector approach are: JSS, emotion, glamorous.
Radium
Radium is created by confuse/CONFUSING and has a CSS-in-JS library on Github with more than 7.2K star. The main difference between Radium and Styled – Components is that it generates inline styles for tags. Because tag inline style in handling such as media Query and :hover, :focus, :active and browser state related style is very inconvenient, so Radium for these styles encapsulate some standard interface and abstraction.
Here’s another example of Radium’s CSS-in-JS Playground:
From the above example, we can see that radium has a very different style definition syntax from styled components, which requires you to use the style attribute to add the appropriate style to the DOM. Open DevTools to see the CSS generated by Radium:
As you can see from the inspect results above in DevTools, Radium generates inline styles directly within the tag. Inline styles have the following advantages over the CSS selector approach:
- The effects of the local style scope come with no additional operations
- An inline style has the highest weight and can avoid weight collisions
- Because the style is written directly in HTML, it is very easy for developers to debug
The other difference
In addition to the differences in the generated CSS style and syntax, different CSS-in-JS implementations also implement different functions. In addition to some of the most basic functions such as CSS local scope, some implementations include and others do not support the following functions:
- Automatically generates the browser engine prefix – built-in vendor Prefix
- Support extraction of separate CSS stylesheets – EXTRACT CSS file
- Built-in support for animations
- Pseudo classes – pseudo classes
- Media query – media query
- other
To learn more about how different CSS-in-Js compare, take a look at this diagram of the different implementations put together by Michele Bertoli.
benefits
After looking at some of the different implementations, you should have a general understanding of the basic concepts and usage of CSS-In-JS, and then we can talk about the benefits and disadvantages of CSS-in-JS.
Local Styles – Scoping Styles
One of the most notorious problems with CSS is that it has no local scope and all declared styles are global. In other words, any element on the page that matches a selector’s rule will be applied and cascading between the rules can be applied. This problem becomes even more acute as SPA applications become popular, because for SPA applications all page style code is loaded into the same environment, and the probability of style conflicts is greatly increased. Because of this problem, we encounter the following problems in our daily development:
- It’s hard to name a selector. To avoid conflicts with the styles of other elements on the page, we need to be very deliberate in choosing selector names that are not too generic. For example, suppose you define a name for a DOM node on a page that serves as a title
.title
The class name is likely to conflict with or will conflict with other selectors on the page, so you have tomanualAdd some prefixes to the class name, for example.home-page-title
To avoid this problem. - Teamwork is difficult. When multiple people are working on the same project, especially when multiple branches are working on it at the same time, there may be conflicting selector names, but this problem is rarely detected in local indie development. When everyone’s code is merged into the same branch, some style problems arise.
Css-in-js provides automatic CSS scoping, so that the styles you define for a component are limited to that component without affecting the styles of other components. Different CSS-in-JS libraries may implement local scoping differently, generally limiting the scope of CSS styles by generating unique selectors for the styles of components. Here is a simplified example of csS-in-JS library generating a unique selector:
const css = styleBlock= > {
const className = someHash(styleBlock);
const styleEl = document.createElement('style');
styleEl.textContent = `.${className} {
${styleBlock}
}
`;
document.head.appendChild(styleEl);
return className;
};
const className = css(` color: red; padding: 20px; `); // 'c23j4'
Copy the code
As you can see from the code above, the IMPLEMENTATION of CSS-in-JS generates a unique CSS selector based on the defined style string and inserts the corresponding style into the style tag in the header of the page, styled Components using a similar method.
Avoid Dead Code Elimination, the accumulation of useless CSS styles
Those of you who have worked on large Web projects have experienced this: When developing new features or refactoring code, there is no explicit one-to-one correspondence between HTML code and CSS styles, so it is difficult to identify which CSS styles are useful and which are not, which makes it difficult to remove potentially useless styles from your code. This way, over time, CSS styles in the project will only increase in stylesheets, not decrease. Useless style code accumulation can lead to the following problems:
- As projects become more heavyweight, more CSS styles are loaded into the browser, which can have a performance impact.
- Developers find it difficult to understand the style code in their projects, and can even be intimidated by the amount of style code, which leads to a decrease in development efficiency and some bizarre style problems.
Css-in-js is a good way to solve this problem. For the Style components writer, Max Stoiber, says:
“For three years, I have styled my web apps without any.css files. Instead, I have written all the CSS in JavaScript. … I can add, change and delete CSS without any unexpected consequences. My changes to the styling of a component will not affect If I delete a component, I delete its CSS too. No more append-only stylesheets!” – Max Stoiber
Max Stoiber basically says that since CSS-in-JS binds styles to components, when a component is to be removed, it is simply removed without worrying about how the style code will affect the styles of other components in the project. And because CSS is written in JavaScript, we can also use JS explicit variable definitions, module references and other language features to track the use of style, which greatly facilitates the change or reconstruction of style code.
Critical CSS
The browser must download and parse the CSS file referenced by our page before rendering it to the user, so the link is a render-blocking CSS resource. If the CSS file is very large or the network is in poor condition, rendering blocked CSS can seriously affect the user experience. One of the best solutions to this problem is to place some Critical CSS directly in the header’s style tag and load the rest asynchronously so that the browser can render the page after parsing the HTML. This is similar to the following code:
<html>
<head>
<style>
/* critical CSS */
</style>
<script>asyncLoadCSS("non-critical.css")</script>
</head>
<body>. body goes here</body>
</html>
Copy the code
So how do you define Critical CSS? Of course, less CSS in the head tag is better, because too much content increases the size of the HTML, so we generally extract the least CSS that users need to see above the fold as Critical CSS. Here is a schematic diagram:
CSS above the fold are Critical CSS because they need to be immediately displayed to the user. Because pages display different effects on different devices, the corresponding Critical CSS content will be different, so the extraction of Critical CSS is a very complex process, although there are many corresponding tools in the community, but the effect is not satisfactory. Css-in-js does a good job of supporting Critical CSS generation. In CSS-in-JS, because the CSS is bound to the component, and only when the component is mounted to the page, their CSS styles are inserted into the page’s style tag, it is easy to know which CSS styles need to be sent to the client during the first rendering. Combined with the packaging tool’s Code Splitting feature, you can minimize the Code loaded onto the page to achieve Critical CSS effects. In other words, CSS-in-JS increases the size of the loaded JS file by a small amount without having to make another request for another CSS file. Also, some CSS-in-JS implementations (such as Styled – Components) automatically support Critical CSS.
State-based Styling Definitions
What appeals to me most about CSS-in-JS is its ability to dynamically generate styles based on the state of the component. For SPA applications, especially for pages with complex interactions, the style of the page often changes depending on the state of the component. If you don’t use CSS-in-JS, dealing with these logically complex situations can be cumbersome. For example, let’s say you have a dot on your page that displays different colors depending on the state of the page: green when running, red when stop, and yellow when ready. If you’re using CSS Modules, you might write the following code:
Style. The CSS file
.circle {
... circle base styles
}
.healthy {
composes: circle;
background-color: green;
}
.stop {
composes: circle;
background-color: red;
}
.ready {
composes: circle;
background-color:
}
Copy the code
Index. Js file
import React from 'react'
import styles from './style.css'
const styleLookup = {
healthy: styles.healthy,
stop: styles.stop,
ready: styles.ready
}
export default ({ status }) => (
<div
className={styleLookup[status]}
/>
)
Copy the code
In style.css we use CSS modules inheritance to use the style of the circle base class in different states of CSS classes, and the code looks very redundant and tedious. As CSS-in-JS writes CSS styles directly to the JS file, style reuse and logic judgment are easy, if the above example is styled- Components:
import styled from 'styled-components'
const circleColorLookup = {
healthy: 'green'.stop: 'red'.ready: 'yellow'
}
export default styled.div`... circle base styles background-color:${({ status }) => circleColorLookup[status]};
`
Copy the code
For styled components, the logic is clearer and simpler. If a state needs to be added later, just add a key-value pair for circleColorLookup, and the STYLE. CSS and index.js files need to be changed simultaneously for CSS modules. The code is hard to maintain and expand.
Better packaged component libraries
Everyone in the daily development process may encapsulate some components in different projects to use, if the style of your component using CSS preprocessing scheme is different from another project preprocessing scheme, for example, the component using LESS, the project using CSS Modules, component reuse will become very troublesome. However, if CSS is written in JS, the project that wants to use the packaged component library can do a simple NPM install, which is very convenient.
The bad
Everything has its advantages and disadvantages. Only when we have a clear understanding of both advantages and disadvantages can we make a better judgment. So let’s talk about the downside of CSS-in-JS.
There is a Steep learning curve
This can be explained in two ways. First, CSS-in-JS is for component-based frameworks, which means that to learn CSS-in-JS you have to learn three skills: Component-based frameworks (like React), JavaScript, and CSS. Second, even if you already know how to build SPA applications using React, JavaScript, and CSS, you will have to learn a CSS-in-JS implementation (such as Styled components) and learn a new way of thinking about problems based on component-defined styles. For the first time, our team used styled- Components, and it took a while to adapt and learn how to use the library. Because of the high learning cost, introducing CSS-in-JS into your project may reduce your development efficiency.
Runtime cost – Runtime cost
Most CSS-in-JS libraries generate CSS on the fly. This has two effects. First, the code you send to the client will include the CSS-in-JS runtime code used. This code is generally not small, for example, styled- Components runtime size is 12.42kB min + gzip. If you want your first screen to be small, You have to think about it. Second, most CSS-in-JS implementations generate CSS dynamically on the client side, which means there is a performance cost. This tool allows you to view and measure the performance of different CSS-in-JS implementations due to their different implementation details.
Bad code readability – Unreadable class names
Most CSS-in-JS implementations achieve THE effect of CSS local scope by generating a unique CSS selector. These automatically generated selectors can greatly reduce the readability of code and have an impact on developer debug.
There is No industry standard – No interoperability
Since CSS-in-JS is just a technical idea and there is no community standard or specification to follow, the syntax and functionality of different implementations can vary considerably. This means that you can’t quickly switch from one implementation to another. For example, if you first use Radium in your project, but as the project size grows, you find that Radium may not be suitable for your current business, and the better solution should be styled components. However, because of the style differences, at this point you will have to make radical changes to the code to migrate to the styled components. However, it is gratifying that relevant standards are now being formulated. Interested students can take a look at the Interoperable Style Transfer Format.
Personal thinking and summary
Css-in-js has both advantages and disadvantages, and we must make trade-offs according to our own situation to determine whether to use it in our own projects. Never use a technology for the sake of using a technology. For example, you don’t need it in the following situations:
- You are a beginner to front-end development: Since csS-in-JS is a steep learning curve, there is no need for Web development beginners to learn and they may feel frustrated.
- You just want to make static pages with simple functions: there is no need to use CSS-in-JS for sites with uncomplicated logical interactions.
- You care about the readability of the style name and the debugging experience: csS-in-JS dynamically generated selectors affect the readability of your code and may reduce your debugging efficiency.
On the other hand, if your application’s interaction logic is complex, CSS-in-JS can be a great development convenience for you, and it’s worth a try for those who haven’t used it before.
reference
- An Introduction to CSS-in-JS: Examples, Pros, and Cons
- Why I Write CSS in JavaScript
- Oh No! Our Stylesheet Only Grows and Grows and Grows!
- What actually is CSS-in-JS
- The tradeoffs of CSS-in-JS
- 9 CSS in JS Libraries you should Know in 2019
- Extract Critical CSS
Personal Technology dynamics
The article was first posted on my personal blog
Welcome to pay attention to the public number of green Onions to learn and grow together