<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          如何在 React 中優(yōu)雅的寫(xiě) CSS

          共 5122字,需瀏覽 11分鐘

           ·

          2019-12-27 23:25

          本文首發(fā)于政采云前端團(tuán)隊(duì)博客:如何在 React 中優(yōu)雅的寫(xiě) CSS

          https://www.zoo.team/article/react-css


          7db38f705f9dac67d2c6d383d6a99f55.webp

          引言

          問(wèn)題:CSS 文件分離 != ?CSS 作用域隔離

          看下這樣的目錄結(jié)構(gòu):

          ├── src? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ??
          │? ?├──......? ? ? ? ? ? ? ? ? ?# 公共組件目錄
          │? ?├── components? ? ? ? ? ? ? # 組件
          │? ?│? ?└──comA? ? ? ? ? ? ? ? ?# 組件A
          │? ?│? ? ? ?├──comA.js? ? ? ? ? ? ? ? ? ? ?
          │? ?│? ? ? ?├──comA.css? ? ? ? ? ? ? ? ? ? ??
          │? ?│? ? ? ?└── index.js? ? ? ? ? ? ? ? ??
          │? ?│? ?└──comB? ? ? ? ? ? ? ? ?# 組件B
          │? ?│? ? ? ?├──comB.js? ? ? ? ? ? ? ? ? ? ?
          │? ?│? ? ? ?├──comB.css? ? ? ? ? ? ? ? ? ? ??
          │? ?│? ? ? ?└── index.js? ? ? ? ? ? ? ? ??
          │? ?├── routes? ? ? ? ? ? ? ? ? # 頁(yè)面模塊? ? ? ? ? ? ? ? ??
          │? ?│? ?└── modulesA? ? ? ? ? ? # 模塊A
          │? ?│? ? ? ?├──pageA.js? ? ? ? ?# pageA JS 代碼
          │? ?│? ? ? ?├──pageA.css? ? ? ? # pageA CSS 代碼

          看目錄結(jié)構(gòu)清晰明了,由于“ CSS 文件分離 != ?CSS 作用域隔離”這樣的機(jī)制,如果我們不通過(guò)一些工具或規(guī)范來(lái)解決 CSS 的作用域污染問(wèn)題,會(huì)產(chǎn)生非預(yù)期的頁(yè)面樣式渲染結(jié)果。

          假設(shè)我們?cè)诮M件 A 和組件 B ?import 引入 comA.css 和 comB.css。

          comA.css

          .title {
          color: red;
          }

          comB.css

          .title {
          font-size: 14px;
          }

          最后打包出來(lái)的結(jié)果為:

          .title {
          color: red;
          }
          .title {
          font-size: 14px;
          }

          我們希望,comA.css 兩者互不影響,可以發(fā)現(xiàn),雖然 A、B 兩個(gè)組件分別只引用了自己的 CSS 文件,但是 CSS 并沒(méi)有隔離,兩個(gè) CSS 文件是相互影響的!

          隨著 SPA 的流行,JS 可以組件化,按需加載(路由按需加載、組件的 CSS 和 JS 都按需加載),這種情況下 CSS 作用域污染的問(wèn)題被放大,CSS 被按需加載后由于 CSS 全局污染的問(wèn)題,在加載出其他一部分代碼后,可能導(dǎo)致現(xiàn)有的頁(yè)面上會(huì)出現(xiàn)詭異的樣式變動(dòng)。這樣的問(wèn)題加大了發(fā)布的風(fēng)險(xiǎn)以及 debugger 的成本。

          小編我從寫(xiě) Vue 到寫(xiě) React , Vue 的 scoped 完美的解決了 CSS 的作用域問(wèn)題,那么 React 如何解決 CSS 的作用域問(wèn)題呢?

          解決 React 的 CSS 作用域污染方案:

          • 方案一:namespaces
          • 方案二:CSS in JS
          • 方案三:CSS Modules

          方案一:namespaces

          利用約定好的命名來(lái)隔離 CSS 的作用域

          comA.css

          .comA .title {
          color: red;
          }
          .comA .……{
          ……
          }

          comB.css

          .comB .title {
          font-size: 14px;
          }
          .comB .……{
          ……
          }

          嗯,用 CSS 寫(xiě)命名空間寫(xiě)起來(lái)貌似有點(diǎn)累。

          沒(méi)事我們有 CSS 預(yù)處理器,利用 less、sass、stylus 等預(yù)處理器,代碼依然簡(jiǎn)潔。

          A.less

          .comA {
          .title {
          color: red;
          }

          .…… {
          ……
          }
          }

          B.less

          .comB {
          .title {
          font-size: 14px;
          }

          .…… {
          ……
          }
          }

          貌似很完美解決了 CSS 的作用域問(wèn)題,但是問(wèn)題來(lái)了,假設(shè) AB 組件是嵌套組件。

          那么最后的渲染 DOM 結(jié)構(gòu)為:

          <div class="comA">
          <h1 class="title">組件A的titleh1>
          <div class="comB">
          <h1 class="title">組件組件的titleh1>
          div>
          div>

          comA 的樣式又成功作用在了組件 B 上。

          沒(méi)關(guān)系,還有解,所有的 class 名以命名空間為前綴。

          <div class="comA">
          <h1 class="comA__title">組件A的titleh1>
          <div class="comB">
          <h1 class="comB__title">組件組件的titleh1>
          div>
          div>

          A.less

          .comA {
          &__title {
          color: red;
          }
          }

          B.less

          .comB {
          &__title {
          font-size: 14px;
          }
          }

          如果,我們的樣式還遵循 BEM (Block, Element, Modifier) 規(guī)范,那么,樣式名簡(jiǎn)直不要太長(zhǎng)!但是問(wèn)題確實(shí)也解決了,但約定畢竟是約定,靠約定和自覺(jué)來(lái)解決問(wèn)題畢竟不是好方法,在多人維護(hù)的業(yè)務(wù)代碼中這種約定來(lái)解決 CSS ?污染問(wèn)題也變得很難。

          方案二:CSS in JS

          使用 JS 語(yǔ)言寫(xiě) CSS,也是 React 官方有推薦的一種方式。

          從 React 文檔進(jìn)入

          https://github.com/MicheleBertoli/css-in-js ,可以發(fā)現(xiàn)目前的 CSS in JS 的第三方庫(kù)有 60 余種。

          看兩個(gè)比較大眾的庫(kù):

          • reactCSS
          • styled-components

          reactCSS

          支持 React

          、Redux、React Native、autoprefixed、Hover、偽元素和媒體查詢(http://reactcss.com/)

          看下官網(wǎng)文檔 :

          const styles = reactCSS({
          'default': {
          card: {
          background: '#fff',
          boxShadow: '0 2px 4px rgba(0,0,0,.15)',
          },
          },
          'zIndex-2': {
          card: {
          boxShadow: '0 4px 8px rgba(0,0,0,.15)',
          },
          },
          }, {
          'zIndex-2': props.zIndex === 2,
          })
          class Component extends React.Component {
          render() {
          const styles = reactCSS({
          'default': {
          card: {
          background: '#fff',
          boxShadow: '0 2px 4px rgba(0,0,0,.15)',
          },
          title: {
          fontSize: '2.8rem',
          color: this.props.color,
          },
          },
          })
          return (
          <div style={ styles.card }>
          <div style={ styles.title }>
          { this.props.title }
          div>

          { this.props.children }
          div>
          )
          }
          }

          可以看出,CSS 都轉(zhuǎn)化成了 JS 的寫(xiě)法,雖然沒(méi)有學(xué)習(xí)成本,但是這種轉(zhuǎn)變還是有一絲不適。

          styled-components

          styled-components,目前社區(qū)里最受歡迎的一款 CSS in JS 方案(https://www.styled-components.com/)

          const Button = styled.a`
          /* This renders the buttons above... Edit me! */
          display: inline-block;
          border-radius: 3px;
          padding: 0.5rem 0;
          margin: 0.5rem 1rem;
          width: 11rem;
          background: transparent;
          color: white;
          border: 2px solid white;
          /* The GitHub button is a primary button
          * edit this to target it specifically! */
          ${props => props.primary && css`
          background: white;
          color: palevioletred;
          `
          }

          `

          render(
          <div>
          <Button
          href="https://github.com/styled-components/styled-components"
          target="_blank"
          rel="noopener"
          primary
          >

          GitHub
          Button>

          <Button as={Link} href="/docs" prefetch>
          Documentation
          Button>
          div>
          )

          與 reactCSS 不同,styled-components 使用了模板字符串,寫(xiě)法更接近 CSS 的寫(xiě)法。

          方案三:CSS Modules

          利用 webpack 等構(gòu)建工具使 class 作用域?yàn)榫植俊?/p>

          CSS 依然是還是 CSS

          例如 webpack,配置 css-loader 的 options modules: true。

          module.exports = {
          module: {
          rules: [
          {
          test: /\.css$/,
          loader: 'css-loader',
          options: {
          modules: true,
          },
          },
          ],
          },
          };

          modules 更具體的配置項(xiàng)參考:https://www.npmjs.com/package/css-loader

          loader 會(huì)用唯一的標(biāo)識(shí)符 (identifier) 來(lái)替換局部選擇器。所選擇的唯一標(biāo)識(shí)符以模塊形式暴露出去。

          示例:

          webpack css-loader options

          options: {
          ...,
          modules: {
          mode: 'local',
          // 樣式名規(guī)則配置
          localIdentName: '[name]__[local]--[hash:base64:5]',
          },
          },
          ...

          App.js

          ...
          import styles from "./App.css";
          ...

          <header className={styles["header__wrapper"]}>
          <h1 className={styles["title"]}>標(biāo)題h1>

          <div className={styles["sub-title"]}>描述div>
          header>
          div>

          App.css

          .header__wrapper {
          text-align: center;
          }

          .title {
          color: gray;
          font-size: 34px;
          font-weight: bold;
          }

          .sub-title {
          color: green;
          font-size: 16px;
          }

          編譯后端的 CSS,classname 增加了 hash 值。

          .App__header__wrapper--TW7BP {
          ? text-align: center;
          }

          .App__title--2qYnk {
          ? color: gray;
          ? font-size: 34px;
          ? font-weight: bold;
          }

          .App__sub-title--3k88A {
          ? color: green;
          ? font-size: 16px;
          }

          總結(jié)

          (1)如果是 ui 組件庫(kù)中使用

          建議使用 namespaces 方案

          原因:

          • ui 組件庫(kù)維護(hù)人員基本固定,遵守約定的規(guī)范較為容易,可通過(guò)約定規(guī)范來(lái)解決不同組件 CSS 相互影響問(wèn)題
          • 由于 ui 組件庫(kù)會(huì)應(yīng)用于整個(gè)公司的產(chǎn)品,在真正的業(yè)務(wù)場(chǎng)景中,雖然不建議,但是可能無(wú)法避免需要覆蓋組件樣式的特殊場(chǎng)景,如使用其他兩種方式,不能支持組件樣式覆蓋

          (2)如果是業(yè)務(wù)代碼/業(yè)務(wù)組件中使用

          CSS in JS ?/ CSS Modules

          業(yè)務(wù)代碼維護(hù)人員較多且不固定、代碼水平不一致,只通過(guò)規(guī)范來(lái)約束不靠譜,無(wú)法保證開(kāi)發(fā)人員嚴(yán)格遵守規(guī)范,不能根治 CSS 交叉影響問(wèn)題,但是從 debug 角度考慮,建議組件外層都添加一個(gè) namespaces 方面定位組件。然后加之 CSS in JS 或 CSS Modules 方案來(lái)解決 CSS 交叉影響問(wèn)題。

          CSS in JS 和 CSS Modules 誰(shuí)優(yōu)誰(shuí)勝?

          CSS Modules 會(huì)比 CSS in JS 的侵入性更小,CSS in JS 可以和 JS 共享變量,但個(gè)人更喜歡 CSS Modules ,但是誰(shuí)優(yōu)誰(shuí)勝無(wú)法武斷。

          • 如果你的團(tuán)隊(duì)還沒(méi)有使用這任一技術(shù),需要考慮的是團(tuán)隊(duì)成員的感受
          • 如果已經(jīng)在使用其中某一種方案,保持一致性即可,相信并這樣走下去

          推薦閱讀

          我的公眾號(hào)能帶來(lái)什么價(jià)值?(文末有送書(shū)規(guī)則,一定要看)
          每個(gè)前端工程師都應(yīng)該了解的圖片知識(shí)(長(zhǎng)文建議收藏)
          為什么現(xiàn)在面試總是面試造火箭?

          「一個(gè)有溫度的前端號(hào)」

          長(zhǎng)按識(shí)別二維碼關(guān)注

          a5a2147bd42f494c502952397386a6c7.webp

          點(diǎn)贊分享是對(duì)作者最大的支持!

          瀏覽 88
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          評(píng)論
          圖片
          表情
          推薦
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  国产又爽 又黄 免费网站在线 | 刘玥一级婬片A片AAA | 欧美做爱高潮白 | 激情网站五月天 | 大白屁股日本女人视频 |