你不需要 CSS 预处理器
Source: Dev.to
请提供您希望翻译的具体文本内容,我将为您翻译成简体中文并保持原有的格式、Markdown 语法以及技术术语不变。
CSS 预处理器:它们仍然值得吗?
曾经有一段时间,CSS 预处理器看起来像是解决所有 CSS 问题的神奇灵药。只需要学习一种新语法、搭建环境,并在项目中添加几个依赖。但随着时间的推移,Web 技术不断发展,预处理器却仍停留在自己的孤立世界中。因此现在我看不出在开发中使用这些工具的任何理由。
让我们来看看预处理器为我们提供了哪些功能,以及这些特性在当下有多大的价值。
变量、嵌套、运算和作用域
相较于最初的版本,现代 CSS 已经显著成熟。现在你可以:
- 使用
@property创建变量 - 使用
@scope限制选择器的作用域 - 使用
calc描述复杂运算 - 使用嵌套的 CSS 规则
因此,这些特性不再是预处理器的专属优势。
Mixins、Maps 与 Functions
混入(mixin)、映射(map)和函数等复杂数据结构似乎是预处理器的真正优势。但你不觉得在 Web 开发中已经有一种编程语言能够长期实现这些功能了吗?
CSS‑in‑JS 的概念传达了一个重要信息——不要再发明新语言,直接使用 JavaScript。浏览器现在已经支持一类 CSS 构造的 StyleSheets:
CSSStyleSheet– 可构造的样式表document.adoptedStyleSheets– 可以添加到 HTML 文档中shadowRoot.adoptedStyleSheets– 可以添加到 ShadowRoot 中
这使得复用样式和动态修改样式变得更容易,彻底改变了力量的平衡。
Mixin 示例(Sass)
@mixin theme($theme: DarkGray) {
background: $theme;
box-shadow: 0 0 1px rgba($theme, .25);
color: #fff;
}
.info { @include theme; }
.alert { @include theme($theme: DarkRed); }
.success{ @include theme($theme: DarkGreen); }
JS 替代实现
const DarkGray = '169, 169, 169';
const DarkRed = '139, 0, 0';
const DarkGreen= '0, 100, 0';
function theme(value = DarkGray) {
return `
background: ${value};
box-shadow: 0 0 1px rgba(${value}, .25);
color: #fff;
`;
}
const sheet = new CSSStyleSheet();
sheet.replaceSync(
`.info {${theme()}}` +
`.alert {${theme(DarkRed)}}` +
`.success{${theme(DarkGreen)}}`
);
Map 示例(Less)
#colors() {
primary: blue;
secondary: green;
}
.button {
color: #colors[primary];
border: 1px solid #colors[secondary];
}
JS 替代实现
const COLORS = {
primary: 'blue',
secondary: 'green'
};
const sheet = new CSSStyleSheet();
sheet.replaceSync(
`.button {
color: ${COLORS.primary};
border: 1px solid ${COLORS.secondary};
}`
);
Function 示例(Stylus)
add(a, b)
a + b
sub(a, b)
a - b
invoke(a, b, fn)
fn(a, b)
body
padding invoke(5, 10, add)
padding invoke(5, 10, sub)
JS 替代实现
const add = (a, b) => a + b;
const sub = (a, b) => a - b;
const invoke= (a, b, fn) => fn(a, b);
const sheet = new CSSStyleSheet();
sheet.replaceSync(
`body {
padding: ${invoke(5, 10, add)};
padding: ${invoke(5, 10, sub)};
}`
);
所有 CSS 预处理器的功能都可以使用纯 JavaScript 实现——无需额外依赖,也不必绑定到特定框架。那么,使用预处理器到底要付出怎样的代价呢?
Source: …
成本是多少?
让我们逐步了解使用 CSS 预处理器的典型工作流程。
1. 安装预处理器
下面是三个主流预处理器的 Package Phobia 报告:
| 预处理器 | 报告 |
|---|---|
| Sass | ![]() |
| Less | ![]() |
| Stylus | ![]() |
这些库并不算轻量,但许多开发者仍然因为“新体验”因素而安装它们。
2. 学习语法
掌握新语法不可避免地会消耗时间和脑力。即使你学习速度很快,通常也需要几天才能熟悉。
3. 集成到构建流水线
你必须将预处理器加入打包工具(Webpack、Vite 等),配置 source‑maps,并确保它在 CI/CD 流程中正常工作。这会增加一层维护工作。
4. 维护代码库
每当预处理器发布破坏性更新时,你需要升级依赖并可能重构样式代码。
底线
- 现代 CSS 已经提供了变量、嵌套、计算和作用域规则。
- 所有“高级”特性(mixins、maps、functions)都可以使用普通 JavaScript 和原生
CSSStyleSheetAPI 来实现。 - 使用预处理器会引入额外的依赖、学习成本以及构建时的复杂性。
如果你已经依赖于以 JavaScript 为中心的样式解决方案(CSS‑in‑JS、设计令牌等),可能根本不需要单独的预处理器。相反,如果你的团队更倾向于纯 CSS 工作流,并且重视 Sass/Less/Stylus 的使用体验,那么这种取舍仍然可能是可接受的。
选择与项目架构和性能目标相匹配的工具——不要仅仅因为预处理器曾经填补了现代 CSS 现在已关闭的空白而去采用它。
设置构建工具
这其实相当简单(赞美 Vite!)。但随后我们需要意识到问题所在。
我们刚刚从 CSS 转向别的东西,又回来了。这是一段激动人心的冒险,但我们在输出时得到的仍是普通的静态 CSS。这值得吗?
我确信会有人说:“看,你相比手写纯 CSS 节省了大量时间。”
但我投入的精力远比写纯 JS 时要多得多。
此外,新语法总是带来自身的限制。最重要的限制是 适用范围。CSS 预处理器只解决了一个问题,而现在这个问题已经可以在不使用它们的情况下轻松解决。
最后思考
在我看来,使用 CSS 预处理器就像乘坐热气球。虽然能到达目的地,但舒适度不如坐飞机。
构建式样表彻底改变了平衡:现在所有 CSS 未实现的功能都可以直接用 JS 完成。只有在构建式样表之上才有意义去创建任何 CSS‑in‑JS 方案。当我开始使用它们时,缺少 TypeScript 支持、服务器端渲染以及选择器压缩,这促使我产生了 EffCSS 的想法。
了解 CSS 预处理器是有益的——在简历上会显得很亮眼。但在实际工作中几乎不值得使用它们。
祝你前端开发愉快!


