CSS-in-JS 还是传统 CSS?前端新手的样式方案实战指南

技术慢生活
2026-01-03 10:28
阅读 928

大家好,我是掘金上常写教程的全栈工程师。最近在带几个刚入门前端的同学做区块链项目时,他们总问我:“样式到底该用哪种写法?”——有人用 <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 Modules
  • styles.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 方案。原理相通!


七、下一步学习建议

  1. 先掌握传统 CSS + Modules
    这是前端基本功,90% 项目够用。重点学:BEM 命名规范、CSS 变量、媒体查询。

  2. 再尝试 CSS-in-JS
    推荐从 styled-components 开始,然后了解 emotion(更轻量)。

  3. 进阶:探索 CSS-in-JS 高级特性

    • 全局样式:createGlobalStyle
    • 主题系统:<ThemeProvider theme={...}>
    • 服务端渲染优化(SSR)
  4. 区块链前端特别建议
    学习如何用样式反映链上状态,例如:

    • 交易确认数 → 进度条颜色渐变
    • 合约地址有效性 → 输入框边框红/绿
      这些场景 CSS-in-JS 会非常优雅。

结语

样式方案没有银弹。传统 CSS 稳健如磐石,CSS-in-JS 灵动如流水。作为前端,你的任务不是站队,而是根据项目需求选择最合适的工具。

我当初学的时候,花了三个月才明白:技术选型的本质是权衡。希望这篇实战指南能让你少走弯路,快速上手现代前端样式开发!

动手试试吧!两个项目我都放在了 GitHub(搜索 css-vs-css-in-js-blockchain-demo),欢迎 Star 和提 Issue。下次见!

评论 0

最热最新
暂无评论
匿名用户Lv.1
0
影响力
0
文章
0
粉丝