你不需要 CSS 预处理器

发布: (2026年2月8日 GMT+8 17:49)
8 分钟阅读
原文: Dev.to

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 报告:

预处理器报告
SassSass 报告
LessLess 报告
StylusStylus 报告

这些库并不算轻量,但许多开发者仍然因为“新体验”因素而安装它们。

2. 学习语法

掌握新语法不可避免地会消耗时间和脑力。即使你学习速度很快,通常也需要几天才能熟悉。

3. 集成到构建流水线

你必须将预处理器加入打包工具(Webpack、Vite 等),配置 source‑maps,并确保它在 CI/CD 流程中正常工作。这会增加一层维护工作。

4. 维护代码库

每当预处理器发布破坏性更新时,你需要升级依赖并可能重构样式代码。

底线

  • 现代 CSS 已经提供了变量、嵌套、计算和作用域规则。
  • 所有“高级”特性(mixins、maps、functions)都可以使用普通 JavaScript 和原生 CSSStyleSheet API 来实现。
  • 使用预处理器会引入额外的依赖、学习成本以及构建时的复杂性。

如果你已经依赖于以 JavaScript 为中心的样式解决方案(CSS‑in‑JS、设计令牌等),可能根本不需要单独的预处理器。相反,如果你的团队更倾向于纯 CSS 工作流,并且重视 Sass/Less/Stylus 的使用体验,那么这种取舍仍然可能是可接受的。

选择与项目架构和性能目标相匹配的工具——不要仅仅因为预处理器曾经填补了现代 CSS 现在已关闭的空白而去采用它。

设置构建工具

这其实相当简单(赞美 Vite!)。但随后我们需要意识到问题所在。

我们刚刚从 CSS 转向别的东西,又回来了。这是一段激动人心的冒险,但我们在输出时得到的仍是普通的静态 CSS。这值得吗?

我确信会有人说:“看,你相比手写纯 CSS 节省了大量时间。”
但我投入的精力远比写纯 JS 时要多得多。

此外,新语法总是带来自身的限制。最重要的限制是 适用范围。CSS 预处理器只解决了一个问题,而现在这个问题已经可以在不使用它们的情况下轻松解决。

最后思考

在我看来,使用 CSS 预处理器就像乘坐热气球。虽然能到达目的地,但舒适度不如坐飞机。

构建式样表彻底改变了平衡:现在所有 CSS 未实现的功能都可以直接用 JS 完成。只有在构建式样表之上才有意义去创建任何 CSS‑in‑JS 方案。当我开始使用它们时,缺少 TypeScript 支持、服务器端渲染以及选择器压缩,这促使我产生了 EffCSS 的想法。

了解 CSS 预处理器是有益的——在简历上会显得很亮眼。但在实际工作中几乎不值得使用它们。

祝你前端开发愉快!

0 浏览
Back to Blog

相关文章

阅读更多 »

帮助您的 SPA 被发现

我打造了一个让我自豪的东西。没有人能找到它。构建产品是容易的部分。我花了几个月时间打造一个开发者工具——一个真正的产品,能够解决……