CSS-in-JS 还是传统 CSS?前端新手的样式方案实战指南
大家好,我是掘金上常写教程的全栈工程师。最近在带几个刚入门前端的同学做区块链项目时,他们总问我:“样式到底该用哪种写法?”——有人用 <style> 标签,有人用 styled-components,还有人直接在 JS 里写 CSS。这让我想起我当初学前端时也踩过同样的坑:样式管理混乱、类名冲突、主题切换难……于是决定写这篇实战指南,帮你从零搞懂现代前端的两种主流样式方案。
📌 本文目标:不讲理论堆砌,而是通过一个真实的“区块链资产展示卡片”项目,手把手带你体验两种方案的开发流程、优缺点和适用场景。
一、为什么样式方案对前端如此重要?
在传统网页开发中,我们习惯把 HTML、CSS、JS 分开写。但随着前端工程化发展(尤其是 React/Vue 等组件化框架流行),样式与组件的耦合性成了新痛点:
- 类名全局污染(
.button在 A 页面是蓝色,在 B 页面却是红色) - 动态主题切换困难(比如白天/黑夜模式)
- 样式作用域不清晰(删了某个 CSS 文件,结果整个网站布局崩了)
而 CSS-in-JS 和 传统 CSS(含模块化) 就是解决这些问题的两大流派。下面我们就用代码说话!
二、环境准备:5 分钟搭好开发脚手架
💡 提示:本教程使用 React + Vite,因其轻量且适合教学。如果你还没装 Node.js,请先去 nodejs.org 下载 LTS 版。
步骤 1:创建项目
# 创建传统 CSS 项目
npm create vite@latest css-demo -- --template react
cd css-demo
npm install
# 创建 CSS-in-JS 项目(稍后用于对比)
npm create vite@latest css-in-js-demo -- --template react
cd css-in-js-demo
npm install styled-components # 安装主流 CSS-in-JS 库
npm install
步骤 2:启动开发服务器
# 在各自项目目录下运行
npm run dev
打开浏览器访问 http://localhost:5173,看到 Vite 的欢迎页就说明环境 OK 了!
⚠️ 新手注意:如果报错
styled-components not found,请确保在css-in-js-demo目录下执行了安装命令。
三、核心概念:用最简单的话说清区别
传统 CSS 是什么?
就是你熟悉的 .class { color: red; } 写法。它独立于 JS 文件存在,通过 <link> 或 <style> 引入。
优点:
- 学习成本低,所有前端都懂
- 浏览器原生支持,性能好
- 工具链成熟(PostCSS、Sass 等)
缺点:
- 全局作用域 → 类名冲突
- 静态写死 → 动态样式需靠 JS 操作 class
CSS-in-JS 又是什么?
把 CSS 写在 JavaScript 里!比如:
const Button = styled.button`
background: ${props => props.primary ? 'blue' : 'gray'};
color: white;
`;
优点:
- 自动作用域隔离(每个组件样式独立)
- 支持 JS 逻辑(动态主题、props 传参)
- 删除组件时样式自动消失(无残留)
缺点:
- 增加包体积(需引入第三方库)
- 运行时生成 CSS(轻微性能损耗)
- 调试时 class 名是哈希值(如
sc-1a2b3c4)
🤔 我当初学的时候:以为 CSS-in-JS 是“取代 CSS”,其实它是“用 JS 管理 CSS”的一种模式。
四、实战项目:构建一个区块链资产卡片
假设我们要做一个展示用户加密货币持仓的卡片,包含:
- 资产名称(如 Bitcoin)
- 当前价格(带颜色:涨红跌绿)
- 持仓数量
- 动态背景色(根据资产类型变化)
我们将分别用 传统 CSS 模块化 和 CSS-in-JS(styled-components) 实现。
方案 1:传统 CSS + CSS Modules
✅ 适用场景:团队熟悉 CSS、追求极致性能、不需要复杂动态样式
步骤 1:创建组件文件
在 src/components/AssetCard.jsx 中:
import styles from './AssetCard.module.css';
export default function AssetCard({ name, price, amount, isRising, type }) {
return (
<div className={`${styles.card} ${styles[type]}`}>
<h3 className={styles.name}>{name}</h3>
<p className={`${styles.price} ${isRising ? styles.rising : styles.falling}`}>
${price}
</p>
<p className={styles.amount}>持有: {amount} 个</p>
</div>
);
}
步骤 2:编写 CSS 模块文件
创建 src/components/AssetCard.module.css:
/* 所有类名自动局部作用域 */
.card {
padding: 16px;
border-radius: 8px;
margin: 10px;
box-shadow: 0 2px 8px rgba(0,0,0,0.1);
}
.bitcoin {
background-color: #f7931a; /* BTC 橙色 */
}
.ethereum {
background-color: #627eea; /* ETH 蓝色 */
}
.name {
font-size: 18px;
font-weight: bold;
margin: 0 0 8px 0;
}
.price {
font-size: 20px;
font-weight: bold;
margin: 0 0 8px 0;
}
.rising {
color: #ff4d4f; /* 涨 - 红色 */
}
.falling {
color: #52c41a; /* 跌 - 绿色 */
}
.amount {
margin: 0;
opacity: 0.8;
}
步骤 3:在 App.jsx 中使用
import AssetCard from './components/AssetCard';
function App() {
return (
<div>
<AssetCard
name="Bitcoin"
price="61200"
amount="0.5"
isRising={true}
type="bitcoin"
/>
<AssetCard
name="Ethereum"
price="3400"
amount="5.2"
isRising={false}
type="ethereum"
/>
</div>
);
}
🔍 关键点:
- 文件名带
.module.css→ 启用 CSS Modulesstyles.card会被编译成唯一哈希类名(如AssetCard_card__1a2b3),避免冲突
方案 2:CSS-in-JS(styled-components)
✅ 适用场景:需要高度动态样式、组件库开发、讨厌管理 class 名
步骤 1:安装依赖(前面已做)
npm install styled-components
步骤 2:创建组件
// src/components/AssetCard.js
import styled from 'styled-components';
// 1. 定义带逻辑的样式组件
const Card = styled.div`
padding: 16px;
border-radius: 8px;
margin: 10px;
box-shadow: 0 2px 8px rgba(0,0,0,0.1);
/* 根据 props 动态设置背景 */
background-color: ${props => {
if (props.type === 'bitcoin') return '#f7931a';
if (props.type === 'ethereum') return '#627eea';
return '#f0f0f0';
}};
`;
const Name = styled.h3`
font-size: 18px;
font-weight: bold;
margin: 0 0 8px 0;
`;
const Price = styled.p`
font-size: 20px;
font-weight: bold;
margin: 0 0 8px 0;
color: ${props => props.isRising ? '#ff4d4f' : '#52c41a'};
`;
const Amount = styled.p`
margin: 0;
opacity: 0.8;
`;
// 2. 组装组件
export default function AssetCard({ name, price, amount, isRising, type }) {
return (
<Card type={type}>
<Name>{name}</Name>
<Price isRising={isRising}>${price}</Price>
<Amount>持有: {amount} 个</Amount>
</Card>
);
}
步骤 3:App.jsx 使用(完全一样!)
import AssetCard from './components/AssetCard';
function App() {
return (
<div>
<AssetCard
name="Bitcoin"
price="61200"
amount="0.5"
isRising={true}
type="bitcoin"
/>
<AssetCard
name="Ethereum"
price="3400"
amount="5.2"
isRising={false}
type="ethereum"
/>
</div>
);
}
🔍 关键点:
- 每个
styled.XXX返回一个 React 组件- 通过
props传参实现动态样式(无需写条件 class)- 样式与组件定义在一起,高内聚!
五、对比总结:一张表看懂怎么选
| 维度 | 传统 CSS (Modules) | CSS-in-JS (styled-components) |
|---|---|---|
| 学习曲线 | ⭐⭐ (前端基础必备) | ⭐⭐⭐ (需理解 JS 闭包、模板字符串) |
| 作用域 | 通过文件名哈希隔离 | 自动组件级隔离 |
| 动态样式 | 需组合多个 class | 直接用 JS 表达式 |
| 性能 | 原生 CSS,最快 | 运行时生成,轻微开销 |
| 调试体验 | DevTools 直接看类名 | 类名为哈希,但可配 readableNames |
| 主题切换 | 需 CSS 变量或重写 class | 通过 ThemeProvider 轻松实现 |
| 适用项目 | 企业后台、内容型网站 | 中后台系统、组件库、区块链 DApp |
💡 区块链项目特别提示:
如果你在开发 Web3 DApp(如钱包、NFT 市场),界面常需根据链上数据动态变色(如 Gas 费高低、代币涨跌),CSS-in-JS 的动态能力会大幅简化代码。
六、新手常见问题解答
Q1:CSS Modules 和普通 CSS 有什么区别?
普通 CSS 是全局的,CSS Modules 通过文件名+哈希让类名局部化。只需把
.css改成.module.css并用import styles from ...即可。
Q2:CSS-in-JS 会让打包体积变大吗?
会。
styled-components约 15KB(gzip 后)。但对现代网络来说影响微乎其微,除非做超轻量级 landing page。
Q3:能不能混用两种方案?
完全可以! 我们团队就在同一个项目里:
- 基础布局用传统 CSS(如 reset.css)
- 复杂交互组件用 CSS-in-JS
Q4:Vue 用户怎么办?
Vue 有
<style scoped>(类似 CSS Modules),也有@vue-styled等 CSS-in-JS 方案。原理相通!
七、下一步学习建议
先掌握传统 CSS + Modules
这是前端基本功,90% 项目够用。重点学:BEM 命名规范、CSS 变量、媒体查询。再尝试 CSS-in-JS
推荐从styled-components开始,然后了解emotion(更轻量)。进阶:探索 CSS-in-JS 高级特性
- 全局样式:
createGlobalStyle - 主题系统:
<ThemeProvider theme={...}> - 服务端渲染优化(SSR)
- 全局样式:
区块链前端特别建议
学习如何用样式反映链上状态,例如:- 交易确认数 → 进度条颜色渐变
- 合约地址有效性 → 输入框边框红/绿
这些场景 CSS-in-JS 会非常优雅。
结语
样式方案没有银弹。传统 CSS 稳健如磐石,CSS-in-JS 灵动如流水。作为前端,你的任务不是站队,而是根据项目需求选择最合适的工具。
我当初学的时候,花了三个月才明白:技术选型的本质是权衡。希望这篇实战指南能让你少走弯路,快速上手现代前端样式开发!
动手试试吧!两个项目我都放在了 GitHub(搜索 css-vs-css-in-js-blockchain-demo),欢迎 Star 和提 Issue。下次见!

评论 0