CSS-in-JS vs 传统CSS:现代样式方案选择指南
大家好,我是小林,一名985毕业的全栈工程师,也是掘金上的一名技术博主。最近在带实习生时发现,很多刚接触 React 的同学对“样式怎么写”这个问题特别迷茫——到底是用传统的 .css 文件?还是用 styled-components 这类 CSS-in-JS 方案?我当初学的时候也踩过不少坑,所以今天就来写一篇零基础也能看懂的对比教程,帮你理清思路,做出适合自己的技术选型。
一、为什么会有两种样式写法?
在前端开发中,样式(CSS) 是让网页“好看”的关键。但在 React 这样的组件化框架中,传统的全局 CSS 容易造成样式冲突和难以维护的问题。
于是社区提出了 CSS-in-JS 的概念:把 CSS 写在 JavaScript 里,和组件绑定在一起。这样每个组件的样式都是独立的,不会互相干扰。
✅ 简单说:
- 传统 CSS:样式写在
.css文件里,通过className引用- CSS-in-JS:样式直接写在 JS/JSX 里,和组件代码放一起
二、环境准备(以 Vite + React 为例)
我们用最简单的工具链来演示。打开终端,执行以下命令:
# 创建项目
npm create vite@latest my-style-demo -- --template react
cd my-style-demo
# 安装依赖
npm install
# 启动开发服务器
npm run dev
现在你有了一个干净的 React 项目。接下来我们分别实现两种样式方案。
三、核心概念对比
1. 传统 CSS 写法
这是最经典的方式:创建 .css 文件,定义类名,然后在 JSX 中通过 className 使用。
优点:简单直观,浏览器原生支持,学习成本低
缺点:类名全局污染,难以实现动态样式
示例代码
// App.jsx
import './App.css';
function App() {
return (
<div className="card">
<h2>这是传统 CSS</h2>
</div>
);
}
export default App;
/* App.css */
.card {
padding: 16px;
background-color: #f0f0f0;
border-radius: 8px;
}
2. CSS-in-JS 写法(以 styled-components 为例)
你需要先安装库:
npm install styled-components
然后直接在 JS 中定义“带样式的组件”。
优点:自动作用域隔离、支持动态传参、逻辑与样式更紧密
缺点:需要额外依赖,运行时有一定开销
示例代码
// App.jsx
import styled from 'styled-components';
const StyledCard = styled.div`
padding: 16px;
background-color: #f0f0f0;
border-radius: 8px;
`;
function App() {
return (
<StyledCard>
<h2>这是 CSS-in-JS</h2>
</StyledCard>
);
}
export default App;
四、实战:做一个带主题切换的按钮
我们来做一个小功能:点击按钮切换“亮色/暗色”主题。这能很好体现两种方案的差异。
方案一:传统 CSS 实现
// Button.jsx
import './Button.css';
import { useState } from 'react';
export default function Button() {
const [darkMode, setDarkMode] = useState(false);
return (
<button
className={`btn ${darkMode ? 'btn-dark' : 'btn-light'}`}
onClick={() => setDarkMode(!darkMode)}
>
切换主题(传统 CSS)
</button>
);
}
/* Button.css */
.btn {
padding: 8px 16px;
border: none;
border-radius: 4px;
cursor: pointer;
font-size: 14px;
}
.btn-light {
background-color: #ffffff;
color: #333333;
}
.btn-dark {
background-color: #333333;
color: #ffffff;
}
💡 注意:这里用了两个类名组合,容易出错,且类名是全局的!
方案二:CSS-in-JS 实现(styled-components)
// Button.jsx
import styled from 'styled-components';
import { useState } from 'react';
const StyledButton = styled.button`
padding: 8px 16px;
border: none;
border-radius: 4px;
cursor: pointer;
font-size: 14px;
/* 根据 props 动态设置样式 */
background-color: ${props => props.dark ? '#333333' : '#ffffff'};
color: ${props => props.dark ? '#ffffff' : '#333333'};
`;
export default function Button() {
const [darkMode, setDarkMode] = useState(false);
return (
<StyledButton
dark={darkMode}
onClick={() => setDarkMode(!darkMode)}
>
切换主题(CSS-in-JS)
</StyledButton>
);
}
✅ 优势很明显:
- 样式和逻辑在一个文件
- 通过
props直接控制样式,无需管理多个类名- 自动避免命名冲突
五、技术选型对比表
| 对比维度 | 传统 CSS | CSS-in-JS(如 styled-components) |
|---|---|---|
| 学习成本 | ⭐ 极低(HTML/CSS 基础即可) | ⭐⭐ 需要理解 JS 模板字符串、props |
| 作用域 | 全局(需靠命名规范避免冲突) | 组件级(自动隔离) |
| 动态样式 | 需切换 class,较繁琐 | 直接通过 props 控制,非常灵活 |
| 性能 | 静态文件,加载快 | 运行时生成 CSS,有轻微开销 |
| 工具链支持 | 所有编辑器原生支持 | 需要插件(如 VS Code 的 styled-components 插件) |
| 调试体验 | 浏览器 DevTools 直接查看 | 生成的 class 名较乱,但可配置 |
| 适用场景 | 简单项目、静态页面 | 复杂交互、主题系统、组件库开发 |
六、新手常见问题解答
Q1:CSS-in-JS 会不会很慢?
答:对于绝大多数应用,性能差异可以忽略。现代 CSS-in-JS 库(如 emotion)做了大量优化。只有在极端高性能场景(如动画密集的 Canvas 应用)才需要谨慎评估。
Q2:我该从哪种开始学?
答:如果你是完全零基础,建议先掌握传统 CSS。因为:
- 它是 Web 开发的基石
- 理解盒模型、布局等概念后,再学 CSS-in-JS 更容易
等你熟悉 React 组件后,再尝试 CSS-in-JS。
Q3:能不能混用?
答:完全可以!比如:
- 页面整体布局用传统 CSS(如
layout.css) - 可复用的 UI 组件用 CSS-in-JS
很多大厂项目都是混合使用。
Q4:有没有不依赖运行时的 CSS-in-JS?
答:有!比如 Linaria 或 Vanilla Extract,它们在构建时就把 JS 转成静态 CSS,兼顾了作用域隔离和性能。不过对初学者稍复杂,建议后期再了解。
七、学习建议与避坑指南
🚶♂️ 学习路径推荐
- 先掌握基础 CSS:盒模型、Flex/Grid 布局、响应式设计
- 熟练使用 React 组件和 props
- 尝试 styled-components:从简单按钮、卡片开始
- 进阶学习:CSS Modules(传统 CSS 的模块化方案)、Tailwind CSS(实用优先的原子化 CSS)
- 探索现代方案:如 Vanilla Extract、Compiled CSS-in-JS
⚠️ 避坑提醒
- 不要为了用新技术而用:如果项目很简单,传统 CSS 完全够用
- 避免过度嵌套:CSS-in-JS 中不要写太深的嵌套选择器,违背组件化思想
- 注意 SSR 支持:服务端渲染时,确保 CSS-in-JS 库正确注入样式(
styled-components默认支持)
结语
我当初学 React 时,也曾纠结“到底该用哪种样式方案”。后来明白:没有银弹,只有合适。传统 CSS 是根基,CSS-in-JS 是利器。作为初学者,先打好基础,再根据项目需求灵活选择。
希望这篇教程能帮你少走弯路。如果你觉得有用,欢迎在掘金关注我,我会持续分享更多零基础友好的前端实战内容!
技术选型的本质,不是追逐潮流,而是解决问题。
—— 你的朋友,小林

评论 0