1. <strong id="7actg"></strong>
    2. <table id="7actg"></table>

    3. <address id="7actg"></address>
      <address id="7actg"></address>
      1. <object id="7actg"><tt id="7actg"></tt></object>

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

        共 5122字,需瀏覽 11分鐘

         ·

        2019-12-27 23:25

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

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


        7db38f705f9dac67d2c6d383d6a99f55.webp

        引言

        問題:CSS 文件分離 != ?CSS 作用域隔離

        看下這樣的目錄結構:

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

        看目錄結構清晰明了,由于“ CSS 文件分離 != ?CSS 作用域隔離”這樣的機制,如果我們不通過一些工具或規(guī)范來解決 CSS 的作用域污染問題,會產生非預期的頁面樣式渲染結果。

        假設我們在組件 A 和組件 B ?import 引入 comA.css 和 comB.css。

        comA.css

        .title {
        color: red;
        }

        comB.css

        .title {
        font-size: 14px;
        }

        最后打包出來的結果為:

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

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

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

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

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

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

        方案一:namespaces

        利用約定好的命名來隔離 CSS 的作用域

        comA.css

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

        comB.css

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

        嗯,用 CSS 寫命名空間寫起來貌似有點累。

        沒事我們有 CSS 預處理器,利用 less、sass、stylus 等預處理器,代碼依然簡潔。

        A.less

        .comA {
        .title {
        color: red;
        }

        .…… {
        ……
        }
        }

        B.less

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

        .…… {
        ……
        }
        }

        貌似很完美解決了 CSS 的作用域問題,但是問題來了,假設 AB 組件是嵌套組件。

        那么最后的渲染 DOM 結構為:

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

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

        沒關系,還有解,所有的 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ī)范,那么,樣式名簡直不要太長!但是問題確實也解決了,但約定畢竟是約定,靠約定和自覺來解決問題畢竟不是好方法,在多人維護的業(yè)務代碼中這種約定來解決 CSS ?污染問題也變得很難。

        方案二:CSS in JS

        使用 JS 語言寫 CSS,也是 React 官方有推薦的一種方式。

        從 React 文檔進入

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

        看兩個比較大眾的庫:

        • reactCSS
        • styled-components

        reactCSS

        支持 React

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

        看下官網文檔 :

        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 都轉化成了 JS 的寫法,雖然沒有學習成本,但是這種轉變還是有一絲不適。

        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 使用了模板字符串,寫法更接近 CSS 的寫法。

        方案三:CSS Modules

        利用 webpack 等構建工具使 class 作用域為局部。

        CSS 依然是還是 CSS

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

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

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

        loader 會用唯一的標識符 (identifier) 來替換局部選擇器。所選擇的唯一標識符以模塊形式暴露出去。

        示例:

        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"]}>標題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;
        }

        總結

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

        建議使用 namespaces 方案

        原因:

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

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

        CSS in JS ?/ CSS Modules

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

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

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

        • 如果你的團隊還沒有使用這任一技術,需要考慮的是團隊成員的感受
        • 如果已經在使用其中某一種方案,保持一致性即可,相信并這樣走下去

        推薦閱讀

        我的公眾號能帶來什么價值?(文末有送書規(guī)則,一定要看)
        每個前端工程師都應該了解的圖片知識(長文建議收藏)
        為什么現在面試總是面試造火箭?

        「一個有溫度的前端號」

        長按識別二維碼關注

        a5a2147bd42f494c502952397386a6c7.webp

        點贊分享是對作者最大的支持!

        瀏覽 88
        點贊
        評論
        收藏
        分享

        手機掃一掃分享

        分享
        舉報
        評論
        圖片
        表情
        推薦
        點贊
        評論
        收藏
        分享

        手機掃一掃分享

        分享
        舉報
        1. <strong id="7actg"></strong>
        2. <table id="7actg"></table>

        3. <address id="7actg"></address>
          <address id="7actg"></address>
          1. <object id="7actg"><tt id="7actg"></tt></object>
            日韩无码电影一区二区 | 丁香五月天婷婷激情综合 | 精品伦一区二区三区妓女 | 91啦丨porny丨国产 | 91丝袜足交 | 99国产精品久久久久久久久久 | 黄片视频A级毛片 | 啊~用力cao嗯cao烂我电影 | 毛片软件在线观看 | 无码一级毛片一区二区视频 |