CSS 模块 vs CSS-in-JS,谁更胜一筹?
介绍
在现代 React 应用程序开发中,组织应用程序样式的方法有很多。其中一种流行的组织方式是 CSS-in-JS 方法(在本文中,我们将使用styled-components作为最流行的解决方案)和 CSS 模块。在本文中,我们将尝试回答这个问题:CSS-in-JS和CSS 模块哪个更好?
让我们回归本质。当网页主要用于存储文本文档,不包含用户交互时,属性就被引入用于设置内容样式。随着时间的推移,网络变得越来越流行,网站规模越来越大,重复使用样式变得必不可少。为此,CSS应运而生。层叠样式表。层叠在这个名字中扮演着非常重要的角色。我们编写的样式就像瀑布一样,覆盖在文档的空隙上,用颜色填充,并突出显示重要的元素。
随着时间的流逝,Web 变得越来越复杂,我们面临的一个问题是样式级联问题。分布式团队各自开发系统的各个部分,将它们组合成可复用的模块,然后像弗兰肯斯坦博士一样,将各个部分拼凑成一个大画布,最终得到意想不到的结果……由于级联的存在,模块 1 的样式可能会影响模块 3 的显示,而模块 4 可能会更改全局样式,最终影响整个应用程序的显示。
开发人员已经开始思考如何解决这个问题。为了避免重叠,他们创建了样式命名约定,例如 Yandex 的 BEM 或 Atomic CSS。其思路很明确:我们使用名称是为了获得可预测性,同时避免重复。
这些方法都被人为因素击溃了。无论如何,我们无法保证 A 团队的开发人员不会使用 C 团队的名称。
命名问题只能通过为 CSS 类分配一个随机名称来解决。这样,我们就得到了一组完全独立的 CSS 样式,它们将应用于特定的 HTML 块,并且我们确信系统的其余部分不会受到任何影响。
随后,两种组织 CSS 的方法应运而生:CSS 模块和CSS-in-JS。从本质上讲,它们采用了不同的技术实现,但实际上解决了编写 CSS 时的原子性、可重用性和避免副作用的问题。
从技术上讲,CSS Modules 使用基于文件名、路径和样式名称的哈希值来转换样式名称。Styled-components 在 JS 运行时处理样式,并在它们进入HTML头部(<head>) 时添加它们。
方法概述
让我们看看哪种方法更适合编写现代 Web 应用程序!
假设我们有一个基本的 React 应用程序:
import React, { Component } from 'react';
import './App.css';
class App extends Component {
render() {
return (
<div className="title">
React application title
</div>
);
}
}
此应用程序的 CSS 样式:
.title {
padding: 20px;
background-color: #222;
text-align: center;
color: white;
font-size: 1.5em;
}
依赖项是 React 16.14、 react-dom 16.14
让我们尝试使用 webpack 和所有生产优化来构建此应用程序。
我们有
丑化后的 JS - 129kb
分离并缩小后的 CSS - 133 字节
CSS 模块中的相同代码如下所示:
import React, { Component } from 'react';
import styles from './App.module.css';
class App extends Component {
render() {
return (
<div className={styles.title}>
React application title
</div>
);
}
}
丑化后的 JS - 129kb
分离并缩小后的 CSS - 151 字节
由于无法压缩生成的长 CSS 名称,CSS 模块版本将占用更多字节。
最后,让我们在 styled-components 下重写相同的代码:
import React, { Component } from 'react';
import styles from 'styled-components';
const Title = styles.h1`
padding: 20px;
background-color: #222;
text-align: center;
color: white;
font-size: 1.5em;
`;
class App extends Component {
render() {
return (
<Title>
React application title
</Title>
);
}
}
丑化 JS - 缺少163kb CSS 文件
CSS 模块和CSS-in-JS(styled-components)之间超过30kb 的差异是由于 styled-components 添加了额外的代码来将样式添加到 HTML 文档的 <head> 部分。
在这个综合测试中,CSS Modules 方法胜出,因为构建系统除了修改类名之外,没有添加任何额外内容来实现它。由于技术实现的原因,Styled-components 添加了依赖项以及用于运行时处理和 <head> 样式的代码。
现在让我们快速了解一下 CSS-in-JS / CSS 模块的优缺点。
优点和缺点
CSS-in-JS
缺点
- 直到 styled-components 解析这些样式并将其添加到 DOM 中时,浏览器才会开始解释这些样式,这会减慢渲染速度。
- 缺少 CSS 文件意味着您无法缓存单独的 CSS。
- 一个关键的缺点是大多数库不支持这种方法,而且我们仍然无法摆脱 CSS。所有原生 JS 和 jQuery 插件都是不使用这种方法编写的。并非所有 React 解决方案都使用它。
- 样式集成问题。当标记开发人员为 JS 开发人员准备布局时,我们可能会忘记传输某些内容;同步新版本的布局和 JS 代码也会很困难。
- 我们不能使用 CSS 实用程序:SCSS、Less、Postcss、stylelint 等。
优点
- 样式可以使用 JS 逻辑。这让我想起了 IE6 中的 Expression,当时我们可以在样式中包装一些逻辑(你好,CSS 表达式 :))。
const Title = styles.h1`
padding: 20px;
background-color: #222;
text-align: center;
color: white;
font-size: 1.5em;
${props => props.secondary && css`
background-color: #fff;
color: #000;
padding: 10px;
font-size: 1em;
`}
`;
- 在开发小模块时,它简化了与项目的连接,因为您只需要连接一个独立的JS文件。
- 从语义上讲,在 React 组件中使用 <Title> 比使用 <h1 className={style.title}> 更好。
CSS 模块
缺点
- 要描述全局样式,您必须使用不属于 CSS 规范的语法。
:global(.myclass) {
text-decoration: underline;
}
- 集成到一个项目中,您需要包含样式。
- 使用 TypeScript 时,您需要自动或手动生成接口。为此,我使用了 Webpack 加载器:
@teamsupercell/typings-for-css-modules-loader
优点
- 我们采用常规 CSS,因此可以使用 SCSS、Less、Postcss、stylelint 等。此外,您无需浪费时间将 CSS 适配到 JS。
- 代码中无需集成任何样式,因此代码非常简洁。
- 除全球风格外,几乎 100% 标准化。
结论
所以,CSS-in-JS 方法的根本问题在于它根本不是 CSS!如果你的团队中只有一位固定的人员负责标记,这种代码会更难维护。由于渲染到文件中的 CSS 是并行处理的,而 CSS-in-JS 无法渲染到单独的 CSS 文件中,因此这类代码的运行速度会更慢。最后一个根本缺陷是无法使用现成的方法和实用程序,例如 SCSS、Less 和 Stylelint 等等。
另一方面,CSS-in-JS 方法对于同时处理标记和 JS 并从头开发所有组件的前端团队来说是一个不错的解决方案。此外,CSS-in-JS 对于集成到其他应用程序的模块也非常有用。
我个人认为,CSS 层叠的问题被高估了。如果我们只与一个团队开发一个小型应用程序或网站,那么我们不太可能遇到名称冲突或组件复用困难的问题。如果您也面临这个问题,我建议您考虑 CSS 模块,因为在我看来,这是针对上述因素的更优解决方案。无论如何,无论您选择哪种方式,都要编写有意义的代码,不要被炒作所迷惑。炒作终将过去,我们都必须接受它。祝愿亲爱的读者们,项目精彩纷呈、妙趣横生!
文章来源:https://dev.to/alexsergey/css-modules-vs-css-in-js-who-wins-3n25