在现代前端工程中,样式管理早已不只是“写点 CSS”这么简单。随着组件化、设计系统与大型应用的普及,传统 CSS 在作用域、复用性、可维护性上的短板逐渐显现,CSS-in-JS 因此成为主流解决方案之一。
但 CSS-in-JS 并非只有一种形态。本文将从整体演进出发,重点介绍两种具有代表性的方案:
- Vanilla Extract:编译时 CSS-in-JS 的典型代表
- Stitches:以运行时性能著称的高性能 CSS-in-JS 库
一、CSS-in-JS 解决了什么问题?
CSS-in-JS 的核心目标,并不是“把 CSS 写进 JS”,而是解决以下长期存在的问题:
- 样式作用域冲突(全局污染)
- 组件与样式强耦合难以维护
- 缺乏类型安全与 IDE 友好支持
- 样式复用与主题切换复杂
- 大型项目中样式不可预测
因此,CSS-in-JS 的价值在于:
让样式成为组件的一等公民,与逻辑、状态、类型系统协同工作。
二、CSS-in-JS 的两种核心路线
从实现机制上看,CSS-in-JS 大致分为两类:
1️⃣ 运行时 CSS-in-JS
- 在浏览器运行时生成样式
- 动态能力强
- 典型代表:styled-components、emotion、Stitches
2️⃣ 编译时 CSS-in-JS
- 在构建阶段生成静态 CSS
- 零运行时开销
- 典型代表:Vanilla Extract、Linaria
本文重点介绍这两条路线中的佼佼者。
三、Vanilla Extract:编译时 CSS-in-JS 的优雅解法
1. 核心理念
Vanilla Extract 的设计理念可以概括为一句话:
用 TypeScript 写样式,在构建阶段生成纯 CSS 文件。
它并不在运行时插入样式,而是通过编译工具将样式提前提取为静态 CSS。
2. 基本示例
// styles.css.ts
import { style } from '@vanilla-extract/css';
export const button = style({
background: 'blue',
color: 'white',
padding: '8px 16px',
borderRadius: 4,
});
最终构建产物是普通的 .css 文件,而不是运行时注入。
3. 核心优势
✅ 零运行时成本
- 不依赖 JS 执行生成样式
- 更利于 SSR、Edge Runtime、低性能设备
✅ 原生 CSS 输出
- 可被浏览器、DevTools、性能工具完整理解
- 更易被优化、缓存
✅ TypeScript 友好
- 样式变量、主题、token 全部类型安全
- 编译期即可发现错误
✅ 强大的主题系统
import { createTheme } from '@vanilla-extract/css';
export const darkTheme = createTheme({
color: {
primary: '#000',
},
});
4. 适用场景
- 组件库 / Design System
- 强 SSR、强性能要求项目
- 需要严格设计 Token 管理的工程
- 希望“CSS 回归 CSS”的团队
四、Stitches:高性能运行时 CSS-in-JS
1. 核心定位
Stitches 是一个强调性能与开发体验平衡的运行时 CSS-in-JS 库,其目标是:
在保留运行时灵活性的同时,尽量降低性能开销。
2. 基本示例
import { styled } from '@stitches/react';
const Button = styled('button', {
backgroundColor: 'blue',
color: 'white',
padding: '8px 16px',
variants: {
size: {
small: { fontSize: '12px' },
large: { fontSize: '16px' },
},
},
});
3. 核心能力
✅ 原子化样式生成
- 相同样式只生成一次
- 避免重复注入 CSS
✅ 强大的 Variants 机制
- 类似组件 API,而非样式 API
- 非常适合设计系统
<Button size="large" />
✅ 极快的运行时性能
- 官方 benchmark 表现优于 styled-components / emotion
- 最小化 DOM 注入次数
✅ 一流的 DX(开发体验)
- API 直观
- 组件即样式
4. 适用场景
- 中大型 React 应用
- 需要高度动态样式的场景
- 快速构建 Design System
- 偏重组件 API 表达的团队
五、Vanilla Extract vs Stitches 对比
| 维度 | Vanilla Extract | Stitches |
|---|---|---|
| 样式生成时机 | 编译时 | 运行时 |
| 运行时成本 | 无 | 极低 |
| 动态能力 | 有限制 | 非常强 |
| TypeScript 支持 | 极强 | 很好 |
| 主题系统 | 强 | 强 |
| SSR / Edge | 非常友好 | 友好 |
| 学习曲线 | 偏工程化 | 偏组件化 |
六、如何选择?
可以用一句话来总结:
- 追求极致性能与可预测性 → Vanilla Extract
- 追求组件化体验与动态能力 → Stitches
在实际项目中,也并非非此即彼:
- 样式 Token、主题 → Vanilla Extract
- 组件层样式表达 → Stitches
七、结语:CSS-in-JS 正在“回归理性”
CSS-in-JS 并没有失败,而是在不断进化:
- 从“运行时一把梭”
- 到“编译时 + 类型系统 + 工程化”
- 再到“性能、DX、可维护性的平衡点”
Vanilla Extract 与 Stitches,正代表了 CSS-in-JS 的两种成熟方向。
选择哪一种,取决于你的团队规模、性能目标与工程理念,而不是流行度本身。
如果你正在构建组件库或设计系统,现在正是重新审视 CSS-in-JS 技术选型的最佳时机。
文章评论