博客 / 詳情

返回

打造高效React應用:CSS方案深度解析

大家好,我是長林啊!一個愛好 JavaScript、Go、Rust 的全棧開發者;致力於終生學習和技術分享。

在React以其聲明式編程範式和組件化架構,成為了構建用户界面的首選技術之一。然而,隨着項目規模的擴大和設計需求的多樣化,如何高效地管理 CSS 樣式成為了每個React開發者都需要面對的挑戰。

本文將從一下三個方面進行介紹,探討如何在 React 中應用和管理樣式,包括內聯樣式、CSS 類、CSS Modules 和 CSS-in-JS 技術,提升界面美觀和開發效率。

常見的樣式方案

在 React 中,組件樣式指的是如何為每個獨立的組件定義和管理視覺表現。組件樣式的設計和應用是 React 開發中的關鍵部分,它決定了應用的外觀和用户體驗。

內聯樣式 (Inline Styles)

在 React 中,內聯樣式是一種直接在元素上定義 CSS 樣式的方式,類似於在 HTML 中使用 style 屬性。不同的是,在 React 中,內聯樣式是通過一個 JavaScript 對象來定義的,而不是傳統的 CSS 字符串。這使得內聯樣式在 React 中具有更強的動態性和靈活性。

基本語法

在 React 中,內聯樣式通過元素的 style 屬性來設置,該屬性接受一個 JavaScript 對象。對象的鍵是 CSS 屬性名(使用駝峯命名法),值是對應的樣式值;如下:

import React from 'react';

function InlineStyles() {
    const divStyle = {
        color: 'blue',
        backgroundColor: 'lightgray',
        padding: '10px',
    };

    return <div style={divStyle}>Hello, World!</div>;
}

export default InlineStyles;

在這個例子中,divStyle 是一個包含樣式屬性的 JavaScript 對象,並通過 style 屬性應用到 div 元素上。

效果如下:

<img src="https://files.mdnice.com/user/8213/24516572-c842-4d4f-8c16-8078892b9c4e.png" style="border:1px solid rgb(222, 198, 251);border-radius: 8px" />

樣式屬性的命名

在 React 的內聯樣式中,CSS 屬性名使用駝峯命名法(camelCase),而不是傳統的 CSS 短橫命名法(kebab-case)。例如:

  • background-color 在 React 中寫成 backgroundColor
  • font-size 寫成 fontSize
  • margin-top 寫成 marginTop

動態樣式

內聯樣式可以非常方便地實現動態樣式。你可以根據組件的狀態或屬性來動態地改變樣式。

import React, { useState } from 'react';

function DynamicStyles() {
    const [isActive, setIsActive] = useState(false);

    const handleClick = () => {
        setIsActive(!isActive);
    };

    const divStyle = {
        color: isActive ? 'red' : 'blue',
        backgroundColor: 'lightgray',
        padding: '10px',
        cursor: 'pointer',
        userSelect: 'none',
    };

    return (
        <div style={divStyle} onClick={handleClick}>
            Click me to change color!
        </div>
    );
}

export default DynamicStyles;

在這個例子中,當點擊 div 元素時會切換其文本顏色。效果圖如下:

<img src="https://files.mdnice.com/user/8213/cee5817c-04da-4b6e-9852-e13bb05d2ce0.gif" style="border:1px solid rgb(222, 198, 251);border-radius: 8px" />

樣式合併

React允許將多個樣式對象合併為一個,這在需要應用多個條件樣式時非常有用:

const baseStyle = { padding: '10px', margin: '5px' };
const activeStyle = { backgroundColor: 'green' };

// 合併樣式
const finalStyle = { ...baseStyle, ...activeStyle };

// ...
<div style={finalStyle} />

內聯樣式的優缺點:

優點:

  • 局部作用域:內聯樣式只作用於當前的元素,不會影響其他元素,避免了樣式衝突。
  • 動態性:可以很方便地根據組件的狀態或屬性來動態設置樣式。
  • 簡潔:對於簡單的樣式,可以減少代碼量和文件數量。

缺點:

  • 可維護性:當樣式變得複雜時,內聯樣式會使得組件代碼變得難以維護。
  • 複用性差:內聯樣式無法複用,相同的樣式需要在多個地方重複定義。
  • 缺少偽類和偽元素支持:內聯樣式無法直接使用 CSS 偽類和偽元素(如 :hover, ::after)。
  • 性能差:聯樣式對象包含大量的屬性或者嵌套的對象,這可能會使得樣式對象的創建和合並更加耗時。

CSS 類 (CSS Classes)

與內聯樣式相比,使用 CSS 類樣式可以使代碼更清晰、可維護性更高。

使用 CSS 類樣式的基本方法

  • 創建 CSS 文件

    首先,你需要創建一個 CSS 文件,並在其中定義你的 CSS 類。例如,創建一個 common.css 文件:

    /* common.css */
    .container {
        color: blue;
        background-color: lightgray;
        padding: 10px;
    }
    
    .active {
        color: red;
    }
  • 在 React 組件中引入 CSS 文件
    在你的 React 組件中,使用 import 語句引入剛剛創建的 CSS 文件:

    import { useState } from 'react';
    import '../assets/styles/common.css';
    
    function ClassStyles() {
        const [isActive, setIsActive] = useState(false);
    
        const handleClick = () => {
            setIsActive(!isActive);
        };
    
        return (
            <div
                className={`container ${isActive ? 'active' : ''}`}
                onClick={handleClick}>
                Click me to change color!
            </div>
        );
    }
    
    export default ClassStyles;

    在這個示例中,我們使用模板字符串(template literals)來動態添加或移除 CSS 類。效果如下:

    <img src="https://files.mdnice.com/user/8213/6e9433f3-653b-4701-b9ff-08989882f0d8.gif" style="border:1px solid rgb(222, 198, 251);border-radius: 8px" />

動態添加或移除 CSS 類

可以使用條件渲染的方法動態添加或移除 CSS 類。例如,使用三元運算符或條件運算符:

<div
    className={`container ${isActive ? 'active' : ''}`}
    onClick={handleClick}>
    Click me to change color!
</div>

或者,使用 classnames、clsx 庫來處理複雜的類名邏輯,下面用 classnames 做個演示:

import { useState } from 'react';
import classNames from 'classnames';

function ClassnamesStyles() {
    const [isActive, setIsActive] = useState(false);

    const handleClick = () => {
        setIsActive(!isActive);
    };

    return (
        <div
            className={classNames('container', { active: isActive })}
            onClick={handleClick}>
            Click me to change color!
        </div>
    );
}

export default ClassnamesStyles;

然後在 App.jsx 中引入 ClassnamesStyles 組件;在這個示例中,classnames 庫使得根據條件判斷類名的處理更加簡潔和易讀。效果如下:

<img src="https://files.mdnice.com/user/8213/191cfe99-2cbd-43a1-b36a-93160f13b5d9.gif" style="border:1px solid rgb(222, 198, 251);border-radius: 8px" />

CSS Modules

為了避免全局樣式衝突,React 推薦使用 CSS 模塊(CSS Modules),它允許你將 CSS 類名限定在本地作用域內。

  • 創建 CSS 模塊文件
    首先,創建一個 CSS 模塊文件,例如 page.module.css:

    /* page.module.css */
    .container {
        color: blue;
        background-color: lightgray;
        padding: 10px;
    }
    
    .active {
        color: red;
    }
  • 在 React 組件中引入和使用 CSS 模塊

    import { useState } from 'react';
    import styles from '../assets/styles/page.module.css';
    
    function CssModuleStyles() {
        const [isActive, setIsActive] = useState(false);
    
        const handleClick = () => {
            setIsActive(!isActive);
        };
    
        return (
            <div
                className={`${styles.container} ${isActive ? styles.active : ''}`}
                onClick={handleClick}>
                Click me to change color!
            </div>
        );
    }
    
    export default CssModuleStyles;

    在這個示例中,CSS 類名是通過 styles 對象來引用的,這樣可以確保類名在本地作用域內不發生衝突。

優缺點對比

優點:

  • 可維護性高:樣式定義集中在一個地方,使得代碼更清晰易讀。
  • 複用性好:相同的樣式可以在多個組件中複用。
  • 避免衝突:使用 CSS 模塊可以避免全局命名衝突。

缺點:

  • 動態性較差:相比於內聯樣式,動態設置樣式略顯不便。
  • 額外的構建步驟:需要引入和配置 CSS 文件,增加了項目的構建複雜度。

Styled Components 和 CSS-in-JS

在 React 中,Styled Components 和 CSS-in-JS 是用於管理和應用樣式的現代解決方案。它們旨在使樣式更加模塊化、可複用和動態化。

Styled Components

Styled Components 是一個流行的 CSS-in-JS 庫,它使用 ES6 的模板字符串語法來定義組件級別的樣式。通過使用 Styled Components,你可以將組件的樣式與其邏輯緊密結合,使得樣式更加模塊化和可維護。

  • 安裝 styled-components 庫

    $ npm install styled-components
  • 使用示例

以下是如何在 React 中使用 Styled Components:

import { useState } from 'react';
import styled from 'styled-components';

// 定義一個帶有樣式的容器組件
const Container = styled.div`
    /* 根據 props.isActive 設置顏色 */
    color: ${props => (props.isActive ? 'red' : 'blue')};
    background-color: lightgray;
    padding: 10px;
    cursor: pointer;
    transition: color 0.3s;
`;

const Button = styled.button`
    /* 根據 props.primary 設置按鈕樣式 */
    background: ${props => (props.$primary ? '#BF4F74' : 'white')};
    color: ${props => (props.$primary ? 'white' : '#BF4F74')};
    font-size: 1em;
    margin: 1em;
    padding: 0.25em 1em;
    border: 2px solid #bf4f74;
    border-radius: 3px;
`;

function StyledComponentsStyles() {
    const [isActive, setIsActive] = useState(false);

    const handleClick = () => {
        setIsActive(!isActive);
    };

    return (
        <main>
            <Container isActive={isActive}>Click me to change color!</Container>
            <Button onClick={handleClick} $primary={isActive}>
                Primary
            </Button>
        </main>
    );
}

export default StyledComponentsStyles;

效果如下:

<img src="https://files.mdnice.com/user/8213/b3ac380e-1237-4434-a043-f2e1258e3f35.gif" style="border:1px solid rgb(222, 198, 251);border-radius: 8px" />

CSS-in-JS

CSS-in-JS 是一種將 CSS 樣式直接寫在 JavaScript 文件中的技術。Styled Components 是 CSS-in-JS 的實現之一,但還有其他庫和方法可以實現 CSS-in-JS,例如 emotion、styled-jsx 等。

優點

  • 模塊化:每個組件的樣式都與組件本身緊密結合,避免了樣式衝突。
  • 動態樣式:可以方便地根據組件的狀態或屬性來動態調整樣式。
  • 可維護性:將組件的樣式和邏輯放在一起,使得代碼更加內聚和可維護。
  • 自動前綴:自動添加瀏覽器前綴,使得樣式兼容更多瀏覽器。

缺點

  • 性能:在某些情況下,CSS-in-JS 可能會對性能產生影響,因為樣式是在運行時生成的。
  • 學習曲線:需要學習新的庫和語法,可能增加項目的複雜性。

其他 CSS-in-JS 庫

  • Emotion
    Emotion 是另一個流行的 CSS-in-JS 庫,具有強大的動態樣式和高性能的特點。
  • 安裝 Emotion

    $ npm install @emotion/react
  • 使用示例

    在使用 emotion 方案的 jsx 文件開頭加入一行 /** @jsxImportSource @emotion/react **/ 的 JSX Pragma(編譯指示),告訴 JS 編譯器使用 @emotion/react 包來替代 React 原生的jsx 運行時。
    /* @jsxImportSource @emotion/react */
    import React from 'react';
    import { css } from '@emotion/react';
    
    const color = 'white';
    
    function EmotionStyles() {
      return (
          <div
              css={css`
                  padding: 32px;
                  font-size: 16px;
                  background-color: hotpink;
                  font-size: 24px;
                  border-radius: 4px;
                  &:hover {
                      color: ${color};
                  }
              `}>
              Hover to change color.
          </div>
      );
    }
    
    export default EmotionStyles;

    效果如下:

<img src="https://files.mdnice.com/user/8213/a9fd13b0-5a57-4b32-b73a-9cafdb204ddf.gif" style="border:1px solid rgb(222, 198, 251);border-radius: 8px" />

emotion 也支持了 style-components 的方案,不過要安裝一下依賴:npm i @emotion/styled,使用示例如下:

/* @jsxImportSource @emotion/react */
import { useState } from 'react';
import styled from '@emotion/styled';

const Container = styled.div`
    color: ${props => (props.isActive ? 'red' : 'blue')};
    background-color: lightgray;
    padding: 10px;
    cursor: pointer;
    transition: color 0.3s;
`;

function EmotionStyledStyles() {
    const [isActive, setIsActive] = useState(false);

    const handleClick = () => {
        setIsActive(!isActive);
    };

    return (
        <Container isActive={isActive} onClick={handleClick}>
            Click me to change color!
        </Container>
    );
}

export default EmotionStyledStyles;

效果如下:

<img src="https://files.mdnice.com/user/8213/4d0c16f4-0cdc-474a-ae35-fc55183b2bc1.gif" style="border:1px solid rgb(222, 198, 251);border-radius: 8px" />

Styled Components 和 CSS-in-JS 是現代 React 開發中非常流行的樣式解決方案。它們提供了模塊化、動態化和高可維護性的樣式管理方式。根據項目需求選擇合適的方案,可以顯著提高開發效率和代碼質量。

總結

在 React 項目中,有許多不同的樣式管理工具和庫可供選擇。以下是一些常見的選擇:

  • CSS-in-JS:Styled Components, Emotion
  • Utility-First CSS 框架:Tailwind CSS、unocss
  • 組件庫:Bootstrap (react-bootstrap), Ant Design, Material-UI等
  • CSS 預處理器:Sass、less
  • CSS 模塊:CSS Modules

選擇合適的樣式管理工具取決於你的項目需求、團隊的熟悉度以及具體的使用場景。

上面的代碼均可以在 clin211/react-awesome 中找到,傳送門。

本文首發在我的微信公眾號【長林啊】,歡迎大家關注、分享、點贊!

user avatar _raymond 頭像 fehaha 頭像 dashnowords 頭像 yihan123 頭像 liujunqi 頭像 huashenjianlingshouhuni 頭像 niaonao 頭像 chouchou_5f11814d4719d 頭像 ni_5e1946a1c2171 頭像 maogexiaodi 頭像 rxliuli 頭像 aixiaodeludan_bqazwx 頭像
15 位用戶收藏了這個故事!

發佈 評論

Some HTML is okay.