CSS-in-JS vs 传统CSS:现代样式方案选择指南
大家好!我是正在读计算机研究生的一名前端爱好者,平时喜欢写技术博客帮助刚入门的新朋友。今天想和大家聊聊一个我当初学前端时非常困惑的问题:CSS 到底该怎么写?
在 React、Vue 等现代框架流行后,“CSS-in-JS” 这个词频繁出现在教程里,而传统的 .css 文件又好像没被淘汰。到底该用哪种方式写样式?它们有什么区别?新手该如何选择?
这篇文章就是为完全零基础的同学准备的。我会用最简单的语言、最实用的例子,带你一步步搞懂这两种主流样式方案,并给出我的最佳实践建议。希望你能看完后不再迷茫!
一、什么是 CSS-in-JS 和传统 CSS?
传统 CSS(Classic CSS)
这是你最早接触的写法:在一个 .css 文件里写样式,然后在 HTML 或组件中通过 class 引用。
<!-- index.html -->
<div class="header">欢迎来到我的网站</div>
/* styles.css */
.header {
color: blue;
font-size: 24px;
}
优点:简单直观,浏览器原生支持,学习成本极低。
CSS-in-JS
这是一种用 JavaScript 写 CSS 的方式。样式不再是独立文件,而是直接写在 JS/TS 组件内部,通常借助第三方库(如 styled-components、Emotion)实现。
// Header.jsx (React 示例)
import styled from 'styled-components';
const Header = styled.div`
color: blue;
font-size: 24px;
`;
export default function App() {
return <Header>欢迎来到我的网站</Header>;
}
优点:样式与组件强绑定、自动避免命名冲突、支持动态样式、便于按需加载。
💡 我当初学的时候以为 CSS-in-JS 是“取代”传统 CSS 的新技术,其实不是!它们是不同场景下的工具选择,就像螺丝刀和锤子,各有用途。
二、开发环境准备(5分钟快速搭建)
为了能实际运行代码,我们需要一个最小化的前端开发环境。这里以 React + Vite 为例(Vite 启动快,适合新手)。
步骤 1:安装 Node.js
去 https://nodejs.org 下载 LTS 版本(长期支持版),安装即可。
验证是否安装成功:
node -v # 应输出 v18.x 或更高
npm -v # 应输出 8.x 或更高
步骤 2:创建项目
打开终端,执行:
npm create vite@latest my-style-project -- --template react
cd my-style-project
npm install
步骤 3:安装 CSS-in-JS 库(可选)
如果你想尝试 CSS-in-JS,比如 styled-components:
npm install styled-components
⚠️ 注意:Vite 默认不支持
styled-components的 SSR(服务端渲染),但对学习完全够用。如果你只学传统 CSS,这步可以跳过。
步骤 4:启动项目
npm run dev
打开浏览器访问 http://localhost:5173,看到 React 欢迎页就说明成功了!
三、核心概念对比:一张表看懂区别
| 对比项 | 传统 CSS | CSS-in-JS |
|---|---|---|
| 文件位置 | 独立 .css 文件 |
写在 JS/TS 组件内 |
| 作用域 | 全局(容易冲突) | 局部(自动隔离) |
| 动态样式 | 需要 JS 操作 class | 直接传 props 控制 |
| 性能 | 静态文件,缓存友好 | 运行时生成,略慢 |
| 学习曲线 | 极低 | 中等(需理解 JS 作用域) |
| 适用场景 | 静态页面、简单项目 | 复杂组件、需要主题切换 |
关键概念解释
1. 作用域(Scope)
- 传统 CSS 中,
.button在任何地方都会生效,如果两个组件都用了.button,样式会互相影响。 - CSS-in-JS 自动生成唯一类名(如
sc-1a2b3c4),确保样式只作用于当前组件。
2. 动态样式
传统 CSS 要实现“根据状态变色”,得写多个 class:
.button { background: gray; }
.button.primary { background: blue; }
<div className={`button ${isPrimary ? 'primary' : ''}`}>按钮</div>
而 CSS-in-JS 可以直接:
const Button = styled.button`
background: ${props => props.primary ? 'blue' : 'gray'};
`;
<Button primary={true}>按钮</Button>
更简洁,逻辑更集中!
四、实战项目:做一个主题切换的卡片组件
我们来动手写一个同时用两种方式实现的卡片组件,体验差异。
项目结构
src/
├── components/
│ ├── CardTraditional.jsx // 传统 CSS 实现
│ └── CardStyled.jsx // CSS-in-JS 实现
├── styles/
│ └── card.css // 传统 CSS 文件
└── App.jsx
方式一:传统 CSS 实现
1. 创建 styles/card.css
.card {
padding: 16px;
border-radius: 8px;
margin: 10px;
box-shadow: 0 2px 4px rgba(0,0,0,0.1);
}
.card.light {
background-color: white;
color: black;
}
.card.dark {
background-color: #333;
color: white;
}
2. 创建 components/CardTraditional.jsx
import '../styles/card.css';
export default function CardTraditional({ theme = 'light', children }) {
return (
<div className={`card ${theme}`}>
{children}
</div>
);
}
3. 在 App.jsx 中使用
import CardTraditional from './components/CardTraditional';
export default function App() {
return (
<div>
<CardTraditional theme="light">浅色卡片</CardTraditional>
<CardTraditional theme="dark">深色卡片</CardTraditional>
</div>
);
}
✅ 优点:清晰分离关注点,设计师可以直接改 CSS。
❌ 缺点:需要手动管理 class 名,容易拼错或冲突。
方式二:CSS-in-JS 实现(使用 styled-components)
1. 安装依赖(如果还没装)
npm install styled-components
2. 创建 components/CardStyled.jsx
import styled from 'styled-components';
const StyledCard = styled.div`
padding: 16px;
border-radius: 8px;
margin: 10px;
box-shadow: 0 2px 4px rgba(0,0,0,0.1);
/* 根据 props 动态设置样式 */
background-color: ${props => props.theme === 'dark' ? '#333' : 'white'};
color: ${props => props.theme === 'dark' ? 'white' : 'black'};
`;
export default function CardStyled({ theme = 'light', children }) {
return <StyledCard theme={theme}>{children}</StyledCard>;
}
3. 在 App.jsx 中替换使用
import CardStyled from './components/CardStyled';
export default function App() {
return (
<div>
<CardStyled theme="light">浅色卡片</CardStyled>
<CardStyled theme="dark">深色卡片</CardStyled>
</div>
);
}
✅ 优点:样式和逻辑在一起,修改方便,无命名冲突。
❌ 缺点:增加了 JS 体积,调试时类名是随机的。
🔍 小技巧:在 styled-components 中,你可以用
attrs或withConfig自定义生成的 class 名,方便调试。
五、新手常见问题解答(FAQ)
Q1:CSS-in-JS 会不会让网页变慢?
答:对于中小型项目,性能差异几乎感知不到。现代库(如 Emotion)做了很多优化。只有在极端高性能场景(如动画密集型应用)才需谨慎。
Q2:我该从哪种开始学?
答:强烈建议先掌握传统 CSS!因为:
- 所有前端框架都支持它
- 面试必考
- 是理解 CSS 原理的基础
等你熟悉组件化开发后,再根据项目需求尝试 CSS-in-JS。
Q3:CSS Modules 是什么?属于哪一类?
答:CSS Modules 是传统 CSS 的“升级版”。它通过编译把 .card 变成 .card_hash123,实现局部作用域。它仍属于传统 CSS 范畴,只是加了作用域隔离。
/* card.module.css */
.card { color: red; }
import styles from './card.module.css';
<div className={styles.card}>...</div>
Q4:Tailwind CSS 算哪一种?
答:Tailwind 是“原子化 CSS”,既不是传统 CSS(不用写 .class{}),也不是 CSS-in-JS(不写在 JS 里)。它是第三种流派,用工具类组合样式。
六、我的最佳实践建议
结合我带实习生的经验,给出以下建议:
🟢 推荐使用传统 CSS 的场景:
- 静态营销页面(如公司官网)
- 小型个人项目
- 团队中有设计师直接交付 CSS
- 学习阶段(打好基础最重要)
🟢 推荐使用 CSS-in-JS 的场景:
- 复杂的 React/Vue 组件库开发
- 需要主题切换、动态皮肤
- 微前端架构(避免样式污染)
- 团队统一使用现代框架
🔧 我的个人配置偏好
- 小项目:传统 CSS + CSS Modules
- 大型 React 项目:Emotion(比 styled-components 更轻量)
- 不推荐在 Vue 中强行用 CSS-in-JS(Vue 的
<style scoped>已足够好)
七、下一步学习路径
- 巩固基础:深入学习 CSS 盒模型、Flex/Grid 布局、响应式设计。
- 进阶工具:了解 PostCSS、Sass(传统 CSS 的增强工具)。
- 探索现代方案:尝试 Tailwind CSS、UnoCSS 等原子化方案。
- 性能优化:学习 Critical CSS、CSS 代码分割等高级技巧。
📌 避坑指南:不要一上来就追求“最新技术”。我见过太多新手跳过 CSS 基础,直接用 CSS-in-JS,结果连
position都不会用,写出的布局全是margin硬调。扎实的基础永远是最快的捷径。
结语
写这篇教程,是因为我深知初学者面对技术选型时的焦虑。CSS-in-JS 并不是“更好”的 CSS,而是“更适合某些场景”的 CSS。
记住:工具没有好坏,只有合不合适。
希望这篇文章能帮你理清思路。如果你有任何疑问,欢迎在评论区留言——虽然这是篇博客,但我真的会看 😄
加油,未来的前端工程师!你的第一个 div 已经写得很棒了。
本文约 3220 字,由一名 211 计算机研究生撰写,坚持做对新人友好的技术分享。

评论 0