運用 CSS in JS 實現模塊化

1、什麼是 CSS in JS


上圖來源:https://2019.stateofcss.com/technologies/javascript

CSS in JS 是2014年推出的一種設計模式,它的核心思想是把 CSS 直接寫到各自組件中,而不是單獨的樣式文件裏。css


CSS in js 的發展:html

  • 最先就是內聯樣式前端

  • 依舊使用 CSS,但使用 JS 來管理樣式依賴,表明是 CSS Modules。java

    這種方式在React框架中引入的。react

  • 使用 JavaScript 生成 CSS 而後插入到頁面中的方式。例如 Styled Components。webpack

    CSS Module 仍是 JS 和 CSS 分離的寫法,而 styled components 其實是在 JS 上寫 CSS了。git

CSS in js 一次又一次的違背了 CSS 與 JS 分離的原則。github

2、常見的 CSS in JS


一、CSS Modules

CSS Modules 能最大化地結合現有 CSS 生態和 JS 模塊化能力,API 簡潔到幾乎零學習成本。web

(1)安裝

CSS Modules 提供各類插件,支持不一樣的構建工具。本文使用的是 Webpack 的css-loader插件。

CSS Modules不侷限於你使用哪一個前端庫,不管是 React、Vue 仍是 Angular,只要你能使用構建工具進行編譯打包就可使用。

本文以 react 爲例。下同。

(2)全局/局部做用域

CSS 是全局的,沒有局部做用域的功能。

但 CSS Modules 默認有局部做用域的概念,實現的方法爲:使用獨一無二的 class 名

這個獨一無二的 class 名,是一個 hash 值,css-loader默認的生成算法是[hash:base64],但 webpack 配置裏面能夠自定義格式。

CSS Modules 只會對 className 以及 id 進行轉換,其餘的好比屬性選擇器,標籤選擇器都不進行處理,推薦儘可能使用 className。

寫法 - js:

import style from './App.css';

<h1 className={style.title_1}>
<h2 className={style.title_2}>

寫法 - css

# 局部做用域的兩種寫法
.title_1 {}

:local(.title_1) {}

# 全局做用域的兩種寫法
:global(.title_2) {}

:global {
  .title_2 {}
  # 還能繼續添加……
}

生成 - html:

<h1 class="_3zyde4l1yATCOkgn-DBWEL">

<h1 class="title_2">

生成 - css:

._3zyde4l1yATCOkgn-DBWEL {}

.title_2{}
(3)拓展 - 實現局部做用域的幾種作法

一、嵌套(很深)選擇器

.widget .table .row .cell .content .header .title {}

二、使用 BEM 的 class 命名規範

用很長的有規則的命名,來儘可能實現惟一標識

className="widget__header--active"

參考我以前的文章《運用 CSS methodologies 去實現模塊化》有介紹 BEM。

三、css modules 的作法

直接用 hash 生成 class 名。即沒有方法1的嵌套,也絕對不會出現方法2中小几率的命名衝突問題。

(4)組合 composition

composes關鍵字可讓一個選擇器能夠繼承另外一個選擇器的規則

很像 less 裏的繼承。

用處:

一、能夠引入別的模塊,是實現模塊化的一個必要功能。

二、還能引入別的模塊的部分樣式。

寫法 - css:

.title-base {
  background-color: blue;
}

# 一、來源於本文件
.title {
  composes: title-base;
  color: red;
}

# 二、或 來源於別的文件
.title {
  composes: title-base from './another.css';
  color: green;
}

生成 - html:

<h1 class="_2DHwuiHWMnKTOYG45T0x34 _10B-buq6_BEOTOl9urIjf8">

生成 - css:

._10B-buq6_BEOTOl9urIjf8 {
 background-color: blue;
}

._2DHwuiHWMnKTOYG45T0x34 {
  color: red;
}

注意:這裏是繼承不是 mixin,因此這裏沒有混入所繼承的選擇器的屬性,而是直接 addon 選擇器名。減小了重複代碼。

(5)使用變量

方法1:PostCSS 和 postcss-modules-values


方法2:搭配 less / sass

:export 關鍵字能夠把 CSS 中的 變量輸出到 JS 中。

/* config.scss */
$primary-color: #f40;

:export {
  primaryColor: $primary-color;
}
/* app.js */

import style from 'config.scss';
// 會輸出 #F40
console.log(style.primaryColor);
(6)結合

一、跟 CSS 預處理器結合

二、跟 BEM 等 CSS methodologies 結合

可參考我以前的一篇文章:CSS methodologies 去實現模塊化

(7)實例

react - jsx :

import classNames from 'classnames';

…………

      <div className={styles.header}>
        <ul className={styles.menu}>
          <li>1</li>
          <li>2</li>
          <li>3</li>
        </ul>
        <div className={styles.account}>
          <button
            type="button"
            className={classNames(styles.btnLogin, {
              [styles.active]: !!this.state.active,
            })}
          >
            login
          </button>
          <button type="button" className={styles.btnRegister}>
            register
          </button>
        </div>
      </div>

react - less :

.header {
  color: blue;
  .menu {
    color: red;
    li {
      color: green;
    }
  }
  .account {
    color: orange;
    .btnLogin {
      font-size: 15px;
    }
    .btnRegister {
      font-size: 20px;
    }
    .btnLogin.active,
    .btnRegister.active {
      font-weight: bold;
    }
  }
}

注意點:

一、由於使用了 css module 因此不用擔憂類名重複。能夠捨棄掉 BEM 那種很長的類名,在保證基本語意化的前提下採起儘可能簡單的類名

二、建議類名爲駝峯,由於 js 裏的 dot 取值形式對駝峯友好,而對styles.btn-login 會報錯。

三、可在 less 中採起 Combined Class Names (如 .btnRegister.active)或 Nested Class Names

四、能夠在 react 中用 classname 庫提升書寫效率(很適合搭配 state / props )。

# classname 用法
classNames('foo', 'bar'); // => 'foo bar'
classNames('foo', { bar: true }); // => 'foo bar'
classNames({ foo: true }, { bar: true }); // => 'foo bar'
classNames({ foo: true, bar: true }); // => 'foo bar'

五、寫好多的styles.xxx很煩怎麼辦?能夠用 babel-plugin-react-css-modules 自動加 styles 前綴。例子:

import React from 'react';
import CSSModules from 'react-css-modules';
import styles from './table.css';

class Table extends React.Component {
    render () {
        return <div styleName='table'>
            <div styleName='row'>
                <div styleName='cell'>A0</div>
                <div styleName='cell'>B0</div>
            </div>
        </div>;
    }
}

export default CSSModules(Table, styles);

另外,還能夠方便的覆蓋本地變量的樣式:

import customStyles from './table-custom-styles.css';<Table styles={customStyles} />;

六、更多實踐請參考 ant design pro (https://pro.ant.design/docs/style-cn),它們用的正是 css modules + less。

二、Styled Components

(1)安裝

npm install styled-components

(2)使用

就拿一個 demo 舉例:

import styled from 'styled-components';

const Wrapper = styled.section`
  margin: 0 auto;
  width: 300px;
  text-align: center;
`;
const Button = styled.button`
  width: 100px;
  color: white;
  background: skyblue;
`;

render(
  <Wrapper>
    <Button>Hello World</Button>
  </Wrapper>
);

注意:Styled Components 不支持 less 和 sass 語法。


因爲 Styled Components 有些激進,本人目前不打算深刻了解。

So,剩餘部分待寫。

拓展


一、CSS 預處理器 和 CSS 後處理器

共同點:CSS 預處理器 和 CSS 後處理器 都屬於 CSS 處理器。

不一樣點:CSS 預處理器使用特殊的語法來標記須要轉換的地方,而 CSS 後處理器能夠解析轉換標準的 CSS,並不須要任何特殊的語法。

CSS 後處理器的表明就是 PostCSS ,PostCSS 是一個平臺,其中最經常使用到的插件就是 autoprefixer

相關文章
相關標籤/搜索