CSS-in-JS:現代 React 開發的樣式解決方案

作者: Calpa Liu
字數:1870
出版:2025 年 3 月 27 日
CSS-in-JS 是一種革命性的樣式技術,它使用 JavaScript 來創建、添加和管理樣式。當 JavaScript 被解析時,CSS 會被動態生成並附加到 DOM 中。這種方法將樣式的抽象提升到了組件級別,使開發者能夠使用 JavaScript 以聲明性和可維護的方式描述樣式。這篇文章將深入探討 CSS-in-JS 的優勢以及如何在 React.js 應用中實現它。

CSS-in-JS 與傳統 CSS 的比較

傳統 CSS 的工作方式

傳統上,我們使用 CSS 樣式表來為網頁設置樣式。在 CSS 中,我們使用選擇器來選擇要設置樣式的元素,並在選擇器內為不同屬性分配值:

p { 
  color: pink; 
  background: blue;
}

CSS-in-JS 的工作方式

相比傳統 CSS 樣式表,CSS-in-JS 是一種使用 JavaScript 創建、添加和管理樣式的技術。使用 CSS-in-JS 時,樣式直接寫在 JavaScript 文件中,並使用 JavaScript 語法。

重要的是,使用 CSS-in-JS 並不能替代對 CSS 的理解。CSS-in-JS 仍然依賴於開發者對 CSS 的基礎知識,包括如何將 CSS 樣式應用於 DOM 元素、樣式如何被繼承以及不同元素的各種屬性等。

CSS-in-JS 的優勢

1. 作用域樣式與命名衝突解決

CSS 有一個全局命名空間,因此在大型應用程序中幾乎不可能避免選擇器衝突。CSS-in-JS 生成唯一的類名(除非刻意覆蓋),有效解決了這個問題。

// 使用 Emotion 的例子
import { css } from '@emotion/react';

const Component = () => (
  <p css={css`color: pink; background: blue;`}>
    這個樣式是作用域內的,不會與其他組件衝突
  </p>
);

2. 動態樣式與基於 props 的樣式變化

CSS-in-JS 允許根據組件 props 或應用狀態輕鬆創建動態樣式,這是傳統 CSS 難以實現的功能。

// 使用 styled-components 的例子
import styled from 'styled-components';

const Button = styled.button`
  padding: 10px;
  background: ${props => props.primary ? 'blue' : 'gray'};
  color: white;
  border-radius: 4px;
`;

// 使用組件
<Button>普通按鈕</Button>
<Button primary>主要按鈕</Button>

3. 提升開發體驗

使用 CSS-in-JS,開發者可以使用 JavaScript 語法編寫樣式,減少在不同語法之間切換的認知負擔。此外,常量和函數可以輕鬆地在 JavaScript 和 CSS 之間共享,降低了代碼重複。

// 共享顏色常量的例子
const colors = {
  primary: '#0d6efd',
  border: '#ddd'
};

function MyComponent({ fontSize }) {
  return (
    <p style={{
      color: colors.primary,
      fontSize,
      border: `1px solid ${colors.border}`
    }}>
      使用 JavaScript 常量和 props 設置樣式
    </p>
  );
}

4. 性能優化

CSS-in-JS 提供了多種性能優化策略:

  • 自動內聯關鍵路徑 CSS
  • 只包含必要的 CSS 聲明,減少代碼量
  • 自動添加供應商前綴,開發者無需考慮兼容性問題
  • 支持靜態提取 CSS,減少運行時開銷

5. 更好的可維護性

CSS-in-JS 使樣式與其組件緊密耦合,便於查找和更新樣式。重構變得更安全,因為樣式現在表示為抽象語法樹,更改選擇器不太可能導致意外的變化。

6. 主題化支持

CSS-in-JS 庫通常提供強大的主題化功能,允許輕鬆管理全局樣式和主題,簡化了創建適應不同主題的響應式設計的過程。

// 使用 ThemeProvider 的主題化例子
import { ThemeProvider } from 'styled-components';

const theme = {
  dark: {
    background: '#333',
    text: '#fff'
  },
  light: {
    background: '#fff',
    text: '#333'
  }
};

function App() {
  return (
    <ThemeProvider theme={theme}>
      <MyComponent />
    </ThemeProvider>
  );
}

React 中常用的 CSS-in-JS 庫

Styled Components

Styled Components 是 React 生態系統中最受歡迎的 CSS-in-JS 庫之一。它使用模板字符串來創建具有樣式的組件。

import styled from 'styled-components';

// 創建一個帶有樣式的 p 元素
const BlueText = styled.p`
  color: blue;
`;

// 使用組件
<BlueText>我的藍色文本</BlueText>

Styled Components 還支持組件繼承和基於 props 的條件樣式:

// 組件繼承
const Button = styled.button`
  padding: 10px;
  border-radius: 4px;
`;

const PrimaryButton = styled(Button)`
  background-color: blue;
  color: white;
`;

// 基於 props 的條件樣式
const DynamicButton = styled.button`
  padding: 10px;
  background: ${props => props.primary ? "lightblue" : "orange"};
  border: 2px solid purple;
  border-radius: 4px;
`;

Emotion

Emotion 是另一個流行的 CSS-in-JS 庫,它提供了更靈活的 API,支持 both styled 方式和 css prop 方式。Emotion 在性能和包大小方面都比 Styled Components 有優勢。

// 使用 styled API (類似 Styled Components)
import styled from '@emotion/styled';

const Button = styled.button`
  padding: 10px;
  background-color: blue;
  color: white;
`;

// 使用 css prop
import { css } from '@emotion/react';

function Component() {
  return (
    <p css={css`color: pink;`}>
      這會變成熱粉色
    </p>
  );
}

根據基準測試,Emotion 在某些場景下的速度可能比 styled-components 快 25 倍,這主要歸功於其高效的樣式處理和緩存機制。

JSS

JSS 使用 JavaScript 對象語法定義樣式,可能對習慣 JavaScript 的開發者更加友好。它通過 HOC 為組件注入 classes 屬性。

import { createUseStyles } from 'react-jss';

const useStyles = createUseStyles({
  myButton: {
    padding: 8,
    '& span': {
      fontWeight: 'bold',
      color: 'white'
    }
  }
});

function Button({ children }) {
  const classes = useStyles();
  return (
    <button className={classes.myButton}>
      {children}
    </button>
  );
}

實際應用:主題管理

使用 CSS-in-JS 可以輕鬆實現主題切換功能。以下是使用 React Context API 和 styled-components 實現亮色和暗色主題切換的例子:

import React, { createContext, useState, useContext } from 'react';
import styled, { ThemeProvider as StyledThemeProvider } from 'styled-components';

// 定義亮色和暗色主題
const themes = {
  light: {
    backgroundColor: '#ffffff',
    primaryColor: '#000000',
  },
  dark: {
    backgroundColor: '#333333',
    primaryColor: '#ffffff',
  },
};

// 創建主題 Context
const ThemeContext = createContext({
  theme: themes.light,
  toggleTheme: () => {},
});

// 主題提供者組件
const ThemeProvider = ({ children }) => {
  const [theme, setTheme] = useState(themes.light);
  
  const toggleTheme = () => {
    setTheme(theme === themes.light ? themes.dark : themes.light);
  };
  
  return (
    <StyledThemeProvider theme={theme}>
      <ThemeContext.Provider value={{ theme, toggleTheme }}>
        {children}
      </ThemeContext.Provider>
    </StyledThemeProvider>
  );
};

// 使用主題的 Hook
const useTheme = () => useContext(ThemeContext);

// 使用主題的組件
const ThemedComponent = () => {
  const { theme, toggleTheme } = useTheme();
  
  return (
    <Container>
      主題切換示例
      當前主題:{theme === themes.light ? '亮色' : '暗色'}
      <Button onClick={toggleTheme}>切換主題</Button>
    </Container>
  );
};

// 樣式化組件
const Container = styled.div`
  background-color: ${props => props.theme.backgroundColor};
  color: ${props => props.theme.primaryColor};
  padding: 20px;
  transition: all 0.3s ease;
`;

const Button = styled.button`
  background-color: ${props => props.theme.primaryColor};
  color: ${props => props.theme.backgroundColor};
  padding: 10px 15px;
  border: none;
  border-radius: 4px;
  cursor: pointer;
`;

// 應用根組件
function App() {
  return (
    <ThemeProvider>
      <ThemedComponent />
    </ThemeProvider>
  );
}

CSS-in-JS 的性能考慮

雖然 CSS-in-JS 提供了許多優勢,但也有一些性能方面的考慮:

運行時開銷

與傳統 CSS 相比,CSS-in-JS 需要在運行時生成和注入樣式,這可能導致額外的 CPU 計算和內存使用。

初始加載和未樣式化內容閃爍

CSS-in-JS 的一個主要問題是在初始頁面加載過程中可能出現未樣式化內容閃爍 (FOUC)。由於樣式是動態注入的,當 HTML 被渲染時它們可能還不可用。

優化策略

為了最大化 CSS-in-JS 的優勢並最小化潛在的缺點,可以採用以下幾種最佳實踐:

  1. 服務器端渲染 (SSR):使用 SSR 最小化 FOUC,確保在頁面渲染前樣式被注入。

  2. 靜態提取:一些庫,如 Emotion 和 Styled Components,提供在構建時靜態提取 CSS 的功能,減少運行時開銷。

  3. 高效緩存:實施緩存策略,防止冗餘重新計算並減少內存消耗。

  4. 條件樣式:避免過度使用在應用程序生命週期中頻繁變化的動態樣式。

結論

CSS-in-JS 代表了前端開發中樣式管理的一個重要進步,特別是在 React 等基於組件的框架中。它通過將樣式與組件邏輯緊密結合,解決了傳統 CSS 的許多限制,如全局命名空間衝突、樣式封裝困難和動態樣式生成的挑戰。

雖然 CSS-in-JS 確實引入了一些運行時開銷和初始加載考慮,但通過適當的優化策略,這些問題可以得到有效緩解。對於現代 React 應用程序,特別是那些規模較大、需要主題化支持或高度動態的應用,CSS-in-JS 提供了一個強大而靈活的解決方案。

無論你選擇 Styled Components 的直觀 API,Emotion 的高性能和靈活性,還是 JSS 的對象語法風格,CSS-in-JS 都能顯著提升你的開發體驗和項目的可維護性。在你的下一個 React 項目中嘗試 CSS-in-JS,體驗它帶來的便利和效率。

關於 Calpa

Calpa 擅長使用 TypeScriptReact.jsVue.js 建立 Responsive Website。

他積極參與開源社區,曾在 2019 年的香港開源大會上擔任講者,提供工作經驗和見解。此外,他也在 GitHub 上公開分享個人博客程式碼,已獲得超過 300 顆星星和 60 個分支的支持。

他熱愛學習新技術,並樂意分享經驗。他相信,唯有不斷學習才能跟上快速演變的技術環境。

熱門文章

最新文章

圖片管理中心
管理圖片資源
IP 查詢
快速查詢和定位 IP 地址的地理位置和相關信息
Python 運行器
無需後端、無需登入,只需打開瀏覽器即可運行 Python 代碼(由 Pyodide 提供支持)
封面圖生成器
自動創建適合各種平台的文章封面圖
原作(青山剛昌)產生器
一鍵創建原作(青山剛昌)的封面圖
日本色彩
探索和使用傳統日本色彩
部落格內容洞察儀表板
以視覺化儀表板方式追蹤文章成效、分享熱度與分類分布,協助創作者掌握內容表現。
蒙特卡羅估算 π
使用蒙特卡羅方法演示 π 值的估算過程
LLM
使用 LLM 模型進行聊天
活動圖生成器
一鍵創建活動的封面圖
Wagmi Card
一鍵創建 Wagmi 的封面圖
Facebook Quote
Facebook Quote
Music Macro Language (MML) Studio
用程式語法編寫旋律,用音符構築想像
Blurhash
一鍵創建 Blurhash
文字分類器
使用 MediaPipe TextClassifier 分類文字
前端工程師免費工具資源
前端工程師免費工具資源
後端工程師免費工具資源
後端工程師免費工具資源
全端工程師免費工具資源
全端工程師免費工具資源
Web3 工程師免費工具資源
Web3 工程師免費工具資源
紫微斗數排盤系統|結合 AI 的命盤性格與事業財務分析生成器
紫微斗數排盤工具,輸入生日與時辰,自動生成完整命盤分析提示(Prompt)。結合最專業紫微理論與 AI 助力,助你深入解析性格、事業、財務與人際課題。免費使用,適合命理師及紫微愛好者。
PixAI Prompt 組合器|快速打造可用於 AI 繪圖的語言拼圖
使用 PixAI 卻不會寫 prompt?這個工具幫你一鍵組裝角色、表情、風格語彙,輸出高品質繪圖提示語句(Prompt),可直接貼入 PixAI 使用。適合插畫師、創作者、AI 新手與 VTuber 角色開發者。