文章目錄
- 1、普通方式-內聯使用css
- 2、引入css文件
- 2.1、示例
- 2.2、classnames
- 3、內聯css與引入css文件對比
- 3.1、內聯css
- 3.2、 外部 CSS 文件(External CSS)
- 4、css module
- 5、sass
- 6、classnames組合scss modules
- 7、css-in-js
- 7.1、CSS-in-JS 的核心特性
- 7.2、主流 CSS-in-JS 庫對比
- 7.3、在 React 中的使用示例
- 7.3.1、使用 styled-components
- 7.3.2、 使用 Emotion(推薦)
- 7.4、CSS-in-JS 的優缺點
- 7.4.1、優點
- 7.4.2、缺點
- 7.5、性能優化策略
- 7.6、與傳統 CSS 方案對比
- 7.7、如何選擇?
- 7.8、最佳實踐
- 結語
1、普通方式-內聯使用css
使用規則:
- 和HTML元素的style類似
- 必須是JS對象的寫法,不能是字符串
- 樣式名要駝峰式寫法,如fontSize
優缺點:
- 優點:優先級最高,適合臨時調試或覆蓋特定樣式。
- 缺點:難以維護,樣式與內容混雜,無法復用。
- 適用場景:快速測試、臨時修復或需要強制覆蓋其他樣式的場景。
2、引入css文件
2.1、示例
- 使用css文件
- JSX中使用className
- 可使用clsx或者classnames做條件判斷
給已發布的div添加額外的樣式,QuestionCard.css如下
.list-item {border: 1px solid #ccc;padding: 10px;margin-bottom: 16px;
}.published {border-color: green;
}
QuestionCard.tsx如下所示:
import { FC, useEffect } from "react";import "./QuestionCard.css";...const QuestionCard: FC<PropsType> = (props) => {
...// 已發布的添加樣式let itemClassName = "list-item";isPublished && (itemClassName = itemClassName + " published");return (<div key={id} className={itemClassName}>...</div>);
};export default QuestionCard;
這種情況,邏輯稍微復雜的話,代碼繁瑣,不方便維護,這里我們用第三方庫classnames來解決,clsx類似,不在演示。
2.2、classnames
詳細安裝使用可以參考下面鏈接1github中介紹,這里直接改造上面樣式,QuestionCard.tsx代碼如下:
import classnames from "classnames";
import "./QuestionCard.css";const QuestionCard: FC<PropsType> = (props) => {...let itemClassName = classnames("list-item", { published: isPublished });...
3、內聯css與引入css文件對比
3.1、內聯css
優點:
-
組件化作用域:樣式天然限定在當前組件,無需擔心全局污染。
-
動態樣式靈活:可直接基于
props
或state
動態計算樣式:jsx
復制
<div style={{ opacity: isActive ? 1 : 0.5 }}>
-
無類名沖突:無需處理類名命名問題。
-
適合快速原型開發:簡單場景下無需維護額外 CSS 文件。
缺點:
- 可維護性差:樣式與邏輯混合,代碼臃腫,難以復用。
- 功能限制:無法直接使用偽類(
:hover
)、媒體查詢、動畫等 CSS 高級特性。 - 性能問題:頻繁更新的動態樣式可能觸發不必要的重渲染。
- 優先級混亂:內聯樣式優先級較高,可能意外覆蓋外部樣式。
適用場景:
- 簡單的動態樣式(如條件顯隱、動態尺寸)。
- 小型組件或臨時調試。
- 需要快速驗證樣式效果的場景。
3.2、 外部 CSS 文件(External CSS)
優點:
- 樣式與邏輯分離:代碼更清晰,符合關注點分離原則。
- 完整 CSS 功能:支持偽類、媒體查詢、動畫等所有 CSS 特性。
- 復用性強:可跨組件復用樣式(如全局主題、工具類)。
- 性能優化:瀏覽器可緩存 CSS 文件,減少重復加載。
- 工具鏈支持:與預處理器(Sass/Less)、PostCSS 無縫集成。
缺點:
- 全局污染風險
4、css module
基本使用,css文件默認命名格式 xxx.module.css,QuestionCard.module.css如下
.list-item {border: 1px solid #ccc;padding: 10px;margin-bottom: 16px;
}.published {border-color: green;
}
QuestionCard.tsx如下:
...
import styles from "./QuestionCard.module.css";const QuestionCard: FC<PropsType> = (props) => {...return (<div key={id} className={styles["list-item"]}>...</div>);
};export default QuestionCard;
效果如下圖所示:
5、sass
-
css語法比較原始,如不能嵌套。
-
現在開發一般使用less、sass等預處理語言
-
Vite等工具原生支持Sass Module,后
第一步:安裝sass
yarn add sass -D
第二步:編輯樣式文件,命名格式 xxxx.module.scss
.list-item {border: 1px solid #ccc;padding: 10px;margin-bottom: 16px;.published-span {color: green;}
}.published {border-color: green;
}
第三步:引入tsx
...
import styles from "./QuestionCard.module.scss";const QuestionCard: FC<PropsType> = (props) => {
...return (<div key={id} className={styles["list-item"]}><strong>{title}</strong> {/* 條件判斷 */}{isPublished ? (<span className={styles["published-span"]}>已發布</span>) : (<span>未發布 </span>)}...</div>);
};export default QuestionCard;
效果如下圖所示;
6、classnames組合scss modules
以上面為例,給已發布的div設置綠色邊框,QuestionCard.tsx如下所示:
...
import styles from "./QuestionCard.module.scss";const QuestionCard: FC<PropsType> = (props) => {
...// 已發布的添加樣式const listItemClass = styles["list-item"];const publishedClass = styles["published"];const itemClassName = classnames({[listItemClass]: true,[publishedClass]: isPublished,});return (<div key={id} className={itemClassName}><strong>{title}</strong> {/* 條件判斷 */}{isPublished ? (<span className={styles["published-span"]}>已發布</span>) : (<span>未發布 </span>)}...);
};export default QuestionCard;
效果如下所示:
7、css-in-js
在 React 和現代前端開發中,CSS-in-JS 是一種將 CSS 樣式直接編寫在 JavaScript/JSX 中的技術方案,它通過組件化的方式管理樣式,解決了傳統 CSS 的全局作用域污染、類名沖突等問題。以下是 CSS-in-JS 的核心解析和主流方案對比:
7.1、CSS-in-JS 的核心特性
特性 | 說明 |
---|---|
組件化作用域 | 樣式與組件綁定,天然隔離,避免全局污染 |
動態樣式 | 基于 props 或 state 動態生成樣式,無需手動切換類名 |
自動廠商前綴 | 自動為 CSS 屬性添加瀏覽器前綴(如 -webkit- ) |
主題支持 | 通過 Provider 模式輕松實現主題切換 |
SSR 支持 | 支持服務端渲染(Server-Side Rendering) |
原子化 CSS | 部分庫(如 Emotion)支持生成原子化 CSS 類,優化性能 |
7.2、主流 CSS-in-JS 庫對比
庫名 | 語法風格 | 優勢 | 缺點 | 適用場景 |
---|---|---|---|---|
styled-components | 模板字符串 | 生態成熟,社區活躍 | 運行時開銷較大 | 通用場景 |
Emotion | 模板字符串/Object | 高性能,支持原子化 CSS | 配置較復雜 | 性能敏感型項目 |
JSS | Object 樣式 | 輕量級,框架無關 | 可讀性較差 | 需要高度定制化的場景 |
Linaria | 模板字符串 | 零運行時,編譯時生成 CSS | 動態樣式受限 | 追求極致性能的靜態站點 |
7.3、在 React 中的使用示例
7.3.1、使用 styled-components
bash
yarn add styled-components
jsx
import { FC } from "react";
import styled from "styled-components";// 基礎組件
const Button = styled.button`padding: 12px 24px;background: ${(props) => (props.primary ? "#1890ff" : "#f5f5f5")};color: ${(props) => (props.primary ? "white" : "#333")};border-radius: 4px;&:hover {opacity: 0.8;}
`;// 繼承樣式
const LargeButton = styled(Button)`padding: 16px 32px;font-size: 18px;
`;const Demo: FC = () => {return (<div><Button>默認按鈕</Button><Button primary>主按鈕</Button><LargeButton>大按鈕</LargeButton></div>);
};export default Demo;
7.3.2、 使用 Emotion(推薦)
bash
yarn add @emotion/react @emotion/styled
jsx
/** @jsxImportSource @emotion/react */
import { css } from '@emotion/react';
import styled from '@emotion/styled';// 1. 使用 css prop
function DynamicComponent({ isActive }) {return (<divcss={css`padding: 20px;background: ${isActive ? '#1890ff' : '#f5f5f5'};&:hover {opacity: 0.8;}`}>動態樣式</div>);
}// 2. 使用 styled API
const StyledButton = styled.button`padding: 12px 24px;border-radius: 4px;${props => props.variant === 'primary' && css`background: #1890ff;color: white;`}
`;function App() {return (<StyledButton variant="primary">Emotion 按鈕</StyledButton>);
}
7.4、CSS-in-JS 的優缺點
7.4.1、優點
- 樣式與組件共存:無需在多個文件間跳轉,提升開發體驗。
- 動態樣式簡便:直接基于組件狀態或 props 驅動樣式變化。
- 自動作用域隔離:避免類名沖突,適合大型項目。
- 主題和設計系統:通過 Context API 實現跨組件主題傳遞。
7.4.2、缺點
- 運行時開銷:動態生成 CSS 可能影響性能(可通過原子化 CSS 優化)。
- 學習成本:需要熟悉新的 API 和模式。
- 調試困難:生成的類名哈希化,開發者工具中可讀性差。
- 包體積增加:引入額外的運行時庫(約 10-20 KB)。
7.5、性能優化策略
-
原子化 CSS
使用@emotion/css
生成原子類,復用樣式聲明:jsx
復制
import { css } from '@emotion/css';const flexCenter = css`display: flex;justify-content: center;align-items: center; `;function Component() {return <div className={flexCenter}>居中內容</div>; }
-
編譯時提取 CSS
使用 Linaria 或 Compiled 在構建時生成靜態 CSS 文件:jsx
復制
// 使用 Linaria import { css } from 'linaria';const title = css`font-size: 24px;color: #333; `;function Component() {return <h1 className={title}>標題</h1>; }
-
避免頻繁樣式更新
對于高頻更新的樣式(如動畫),優先使用 CSS 原生動畫或transform
屬性。
7.6、與傳統 CSS 方案對比
場景 | CSS-in-JS | CSS Modules | 普通 CSS |
---|---|---|---|
作用域管理 | ? 自動隔離 | ? 哈希類名隔離 | ? 需手動管理 |
動態樣式 | ? 基于 props/state | ? 需類名切換 | ? 需類名切換 |
偽類/媒體查詢 | ? 完整支持 | ? 完整支持 | ? 完整支持 |
SSR 支持 | ? 完善 | ? 支持 | ? 支持 |
性能 | ?? 運行時開銷 | ? 高效 | ? 高效 |
適用項目規模 | 中大型動態項目 | 中大型項目 | 小型項目或遺留系統 |
7.7、如何選擇?
- 選擇 CSS-in-JS 的場景:
- 項目需要高度動態的樣式(如主題切換、復雜交互狀態)。
- 團隊偏好組件化開發模式,希望樣式與邏輯緊密耦合。
- 項目規模較大,需嚴格避免樣式沖突。
- 避免 CSS-in-JS 的場景:
- 追求極致性能(如低端設備或動畫密集型應用)。
- 需與非 React 生態共享樣式(如跨框架組件庫)。
- 項目已穩定使用 CSS Modules 或 Tailwind CSS。
7.8、最佳實踐
-
統一樣式模式:團隊約定使用單一方案(如 Emotion),避免混用多種 CSS 方案。
-
主題規范化:使用 ThemeProvider 管理顏色、間距等設計系統變量:
jsx
復制
// 定義主題 const theme = {colors: { primary: '#1890ff' },spacing: { md: '16px' } };// 在根組件傳遞主題 import { ThemeProvider } from '@emotion/react';function App() {return (<ThemeProvider theme={theme}><ChildComponent /></ThemeProvider>); }// 子組件中使用主題 const Button = styled.button`padding: ${props => props.theme.spacing.md};background: ${props => props.theme.colors.primary}; `;
-
結合靜態樣式提取:對首屏關鍵 CSS 使用編譯時工具生成,減少運行時開銷。
CSS-in-JS 是現代 React 生態中強大的樣式方案,尤其適合動態化、組件化的項目需求。根據團隊習慣和性能要求選擇合適的庫,并遵循最佳實踐,可顯著提升開發效率和可維護性。
結語
?QQ:806797785
??倉庫地址:https://gitee.com/gaogzhen
??倉庫地址:https://github.com/gaogzhen
[1]github classnames[CP/OL].
[2]styled-component官網[CP/OL].
[3]Classnames[CP/OL].