1. 程式人生 > 其它 >react中css作用域問題探究

react中css作用域問題探究

場景1

新建元件Page1與Page2,兩個元件的根節點className設定為一樣

目錄結構如下:

src/pages/page1/index.js

import React from 'react'
import './index.css'

function Page1() {
  return (
    <div className='title'>page1</div>
  )
}

export default Page1

src/pages/page1/index.css

.title {
  background-color: #ccc;
}

src/pages/page2/index.js

import React from 'react'
import './index.css'

function Page2() {
  return (
    <div className='title'>page2</div>
  )
}

export default Page2

src/pages/page2/index.css

.title {
  background-color: red;
}

src/app.js

import Page1 from './pages/page1';
import Page2 from './pages/page2';

function App() {
  return (
    <div className="App">
      <header className="App-header">
        <Page1 />
        <Page2 />
      </header>
    </div>
  );
}

export default App;

效果圖如下:

會發現兩個元件之間樣式會相互影響?是因為最終打包出來的樣式渲染到節點上是這樣的:

結論:CSS檔案分離 !== CSS作用域隔離

CSS的一些常見問題

  • 全域性汙染
  • 命名混亂
  • 程式碼關係複雜
  • 無法共享變數
  • 複用性差,難維護

實現CSS樣式隔離的幾種方式

  • 行內樣式,直接在js中編寫css
  • namespaces
  • CSS-in-JS,常見的解決方案有styled-components、styled-jsx、react-style
  • CSS Modules

行內樣式

優點:

  • 寫法簡單
  • 優先順序高,有類似獨立作用域

缺點:

  • 無法複用
  • 內容與樣式沒分離,難維護

src/pages/page5/index.js

import React from 'react'

function Page5() {
  return (
    <div style={{ background: 'red' }}>page5</div>
  )
}

export default Page5

src/pages/page6/index.js

import React from 'react'

function Page6() {
  return (
    <div style={{background: 'green'}}>page6</div>
  )
}

export default Page6

效果圖:

namespaces

通過css樣式變數的命令來做到作用域隔離

優點:

  • 寫法簡單,沒什麼需要特別注意的

缺點:

  • 團隊協作是還是容易出現命名重複的情況出現

src/pages/page7/index.js

import React from 'react'
import styles from './index.less'

function Page7() {
  return (
    <div className={styles.page7}>
      page7
      <p>哈哈哈,我是通過namespaces方案區分的</p>
    </div>
  )
}

export default Page7

src/pages/page7/index.less

.page7 {
  background-color: red;
  p {
    font-size: 15px;
    color: #fff;
  }
}

src/pages/page8/index.js

import React from 'react'
import styles from './index.less'

function Page8() {
  return (
    <div className={styles.page8}>
      page8
      <p>哈哈哈,我是通過namespaces方案區分的</p>
    </div>
  )
}

export default Page8

src/pages/page8/index.less

.page8 {
  background-color: #398def;
  p {
    font-size: 30px;
  }
}

效果圖:

CSS-in-JS

通過寫js的方式來寫css,react官方也是推薦這樣來寫。官方文件

CSS-in-JS地址,可以看到常見的基於CSS-in-JS的解決方案

優點:

  • 解決了css作用域的問題
  • 複用性

缺點:

  • 一定的學習成本
  • 與常見的寫法不同

CSS Module

CSS Module本質是通過三方工具如webpack等,把css的變數唯一化

效果圖:

從上面可以看出,我設定的類名為styles.header,但是在經過編譯後為index__header__2zovj,其實配置一下css-loader開啟css modules即可

配置方式:

{
  test: /\.css$/,
    loader: "style-loader!css-loader?modules"
}

大功告成!!!

總結

其實css作用域的本質,就是頁面中的類名都是唯一的。現在通過編譯工具,可以把頁面中類名編譯為一個唯一的類名,這樣就不會出現類名相同的情況下相互影響。

綜合下來,CSS Module會比CSS-in-JS使用起來更方便,對程式碼的入侵更小,寫法也更符合常見的形式,結合三方工具配置起來也挺方便的。

參考