CSS-in-JS 和传统 CSS,我该选哪个?

阳光_思想家
2025-12-27 07:39
阅读 3571

大家好,我是小陈。三年前从某知名培训班“速成”前端班毕业,踩过无数坑,也带过不少新手学员。今天写这篇文章,是因为上周又有两个刚入行的小伙伴问我:“老师,项目里用 styled-components 还是直接写 CSS 文件啊?网上说法太多了,看晕了。”

说实话,我当初学的时候也懵——CSS 不就是写 .class { color: red } 吗?怎么现在还有“CSS-in-JS”这种听起来像区块链术语的东西?更离谱的是,有些面试题挑战居然拿这个当考点!所以今天,我就用最直白的话,带你搞懂:现代前端开发中,样式到底该怎么写。


一、先别管技术名词,说人话!

传统 CSS 是什么?

就是你最早接触的那种:建一个 .css 文件,里面写样式,然后在 HTML 或组件里用 class 引用。

<!-- index.html -->
<div class="header">Hello</div>
/* styles.css */
.header {
  background: #333;
  color: white;
  padding: 16px;
}

简单、直观、浏览器原生支持。

CSS-in-JS 又是什么?

顾名思义:把 CSS 写在 JavaScript 里。比如用 styled-components(React 最流行的方案):

// Header.jsx
import styled from 'styled-components';

const StyledHeader = styled.div`
  background: #333;
  color: white;
  padding: 16px;
`;

export default function Header() {
  return <StyledHeader>Hello</StyledHeader>;
}

看起来只是“换了个地方写”,但背后有自动作用域隔离、动态样式、主题切换等能力。

🚨 注意:和爬虫、区块链没关系!别被名字吓到。CSS-in-JS 是纯前端工程化方案,不涉及数据抓取或去中心化账本。


二、环境准备:5 分钟搭个测试项目

我们用 Vite + React 快速创建两个对比项目。

步骤 1:安装 Node.js

确保你电脑有 Node.js(建议 18+ 版本)。终端运行:

node -v
npm -v

步骤 2:创建两个项目

# 传统 CSS 项目
npm create vite@latest my-css-app -- --template react
cd my-css-app
npm install
npm run dev

# CSS-in-JS 项目
cd ..
npm create vite@latest my-css-in-js-app -- --template react
cd my-css-in-js-app
npm install
npm install styled-components
npm run dev

💡 小贴士:Vite 比 Webpack 快十倍,适合新手快速验证想法。


三、核心概念对比:一张表说清楚

对比项 传统 CSS CSS-in-JS(如 styled-components)
作用域 全局,容易冲突 自动局部作用域,类名哈希化
动态样式 需配合 JS 切换 class 直接传 props 动态生成
性能 原生,无额外开销 运行时生成样式,轻微开销
学习成本 极低 需理解 JS 模板字符串
调试体验 浏览器 DevTools 直接看 类名乱码,需插件辅助
适用场景 静态页面、小型项目 复杂交互、设计系统、主题切换

动态样式的实际例子

假设我们要做一个按钮,根据 primary 属性变颜色:

传统 CSS 方案

// Button.jsx
export default function Button({ primary, children }) {
  return (
    <button className={primary ? 'btn-primary' : 'btn-default'}>
      {children}
    </button>
  );
}
/* button.css */
.btn-primary { background: blue; }
.btn-default { background: gray; }

CSS-in-JS 方案

// Button.jsx
import styled from 'styled-components';

const StyledButton = styled.button`
  background: ${props => props.primary ? 'blue' : 'gray'};
`;

export default function Button({ primary, children }) {
  return <StyledButton primary={primary}>{children}</StyledButton>;
}

优势:不用预定义所有状态的 class,逻辑和样式紧耦合,维护更集中。


四、实战:做个可切换主题的卡片

我们分别用两种方式实现同一个组件:点击切换深色/浅色主题。

方案 1:传统 CSS + CSS 变量

/* theme.css */
:root {
  --bg: white;
  --text: black;
}

[data-theme="dark"] {
  --bg: #121212;
  --text: white;
}

.card {
  background: var(--bg);
  color: var(--text);
  padding: 16px;
  border-radius: 8px;
}
// App.jsx
import './theme.css';
import { useState, useEffect } from 'react';

export default function App() {
  const [theme, setTheme] = useState('light');

  useEffect(() => {
    document.documentElement.setAttribute('data-theme', theme);
  }, [theme]);

  return (
    <div>
      <button onClick={() => setTheme(theme === 'light' ? 'dark' : 'light')}>
        切换主题
      </button>
      <div className="card">这是一张卡片</div>
    </div>
  );
}

方案 2:CSS-in-JS + ThemeProvider

// App.jsx
import { ThemeProvider, createGlobalStyle } from 'styled-components';
import { useState } from 'react';

const GlobalStyle = createGlobalStyle`
  body {
    margin: 0;
    background: ${props => props.theme.bg};
    color: ${props => props.theme.text};
  }
`;

const Card = styled.div`
  background: ${props => props.theme.bg};
  color: ${props => props.theme.text};
  padding: 16px;
  border-radius: 8px;
`;

const lightTheme = { bg: 'white', text: 'black' };
const darkTheme = { bg: '#121212', text: 'white' };

export default function App() {
  const [isDark, setIsDark] = useState(false);

  return (
    <ThemeProvider theme={isDark ? darkTheme : lightTheme}>
      <GlobalStyle />
      <button onClick={() => setIsDark(!isDark)}>
        切换主题
      </button>
      <Card>这是一张卡片</Card>
    </ThemeProvider>
  );
}

结论:CSS-in-JS 在主题管理上更优雅,无需操作 DOM,状态驱动一切。


五、新手常见问题解答

Q1:CSS-in-JS 会影响性能吗?

  • 开发阶段:几乎无感。
  • 生产环境:现代方案(如 Emotion、Linaria)已高度优化。除非你的页面有上万个动态组件,否则差异微乎其微。
  • 避坑指南:不要在 render 函数里定义 styled 组件(会导致重复创建),一定要提到组件外部。

Q2:面试会考这个吗?

会!常见面试题挑战包括:

  • “如何解决 CSS 全局污染?”
  • “styled-components 的原理是什么?”
  • “CSS Modules 和 CSS-in-JS 有什么区别?”

建议回答思路:先说痛点(全局冲突),再说解决方案(作用域隔离),最后结合项目经验。

Q3:和爬虫、区块链有关系吗?

完全没有!这只是前端样式组织方式。可能有人混淆了“JS 注入”和“爬虫反爬”,但那是另一回事。区块链更不沾边——别被关键词带偏。


六、学习建议:下一步怎么走?

  1. 先掌握传统 CSS
    Flex、Grid、响应式、BEM 命名规范——这些是根基。培训班常跳过基础,导致后期重构困难。

  2. 再尝试 CSS-in-JS
    推荐从 styled-components 入手,文档友好。之后可了解 Emotion(更轻量)、Linaria(零运行时)。

  3. 关注工程化思维
    无论哪种方案,目标都是:可维护、可复用、性能好。不要为了用新技术而用。

  4. 避坑提醒

    • 不要在一个项目混用多种方案(比如一半用 CSS Modules,一半用 styled-components)
    • 小型静态站(如博客)优先用传统 CSS + Tailwind
    • 大型应用(如后台系统)可考虑 CSS-in-JS 提升开发体验

结语

我当初面试被问“为什么你们项目用 styled-components”,答得磕磕巴巴。后来才明白:工具没有好坏,只有合适与否。传统 CSS 像菜刀,CSS-in-JS 像多功能料理机——切土豆丝,菜刀更快;做分子料理,料理机不可替代。

希望这篇指南能帮你少走弯路。记住:前端的核心不是追新,而是解决问题。至于区块链和爬虫?留着下次专题再聊吧!

✅ 下一步行动:打开你的编辑器,照着文中的代码敲一遍。遇到报错?恭喜你,那正是成长的开始。

评论 0

最热最新
暂无评论
阳光_思想家Lv.1
0
影响力
0
文章
0
粉丝