梳理 CSS 模塊化

最近年末,抽出一點時間總結了一下 css 的模塊化。css

  • CSS 發展
  • CSS 模塊化定義
  • CSS 模塊化的實現方式

原文地址,歡迎 Star 和 訂閱 個人博客html

CSS 發展

咱們在書寫 css 的時候其實經歷瞭如下幾個階段:前端

  • 手寫源生 CSS
  • 使用預處理器 Sass/Less
  • 使用後處理器 PostCSS
  • 使用 css modules
  • 使用 css in js

手寫源生 CSS

在咱們最初學習寫頁面的時候,你們都學過怎麼去寫 css,也就如下幾種狀況:vue

  • 行內樣式,即直接在 html 中的 style 屬性裏編寫 css 代碼。
  • 內嵌樣式,即在 html h 中的 style 標籤內編寫 class,提供給當前頁面使用。
  • 導入樣式,即在內聯樣式中 經過 @import 方法,導入其餘樣式,提供給當前頁面使用。
  • 外部樣式,即便用 html 中的 link 標籤,加載樣式,提供給當前頁面使用。

咱們在不斷摸索中,逐漸造成了以編寫內嵌樣式外部樣式爲主要的編寫習慣。react

讀到這裏你們確定有所疑問,爲何不建議使用行內樣式?webpack

使用行內樣式的缺點git

  • 樣式不能複用。
  • 樣式權重過高,樣式很差覆蓋。
  • 表現層與結構層沒有分離。
  • 不能進行緩存,影響加載效率。

而後咱們繼續剖析一下,爲何不建議使用導入樣式?github

經測試,在 css 中使用 @import 會有如下兩種狀況:web

一、在 IE6-8 下,@import 聲明指向的樣式表並不會與頁面其餘資源併發加載,而是等頁面全部資源加載完成後纔開始下載。前端工程化

二、若是在 link 標籤中去 @import 其餘 css,頁面會等到全部資源加載完成後,纔開始解析 link 標籤中 @import 的 css。

使用導入樣式的缺點

  • 導入樣式,只能放在 style 標籤的第一行,放其餘行則會無效。
  • @import 聲明的樣式表不能充分利用瀏覽器併發請求資源的行爲,其加載行爲每每會延後觸發或被其餘資源加載掛起。
  • 因爲 @import 樣式表的延後加載,可能會致使頁面樣式閃爍。

使用預處理器 Sass/Less

隨着時間的不斷髮展,咱們逐漸發現,編寫源生的 css 其實並不友好,例如:源生的 css 不支持變量,不支持嵌套,不支持父選擇器等等,這些種種問題,催生出了像 sass/less 這樣的預處理器。

預處理器主要是強化了 css 的語法,彌補了上文說了這些問題,但本質上,打包出來的結果和源生的 css 都是同樣的,只是對開發者友好,寫起來更順滑。

後處理器 PostCSS

隨着前端工程化的不斷髮展,愈來愈多的工具被前端大佬們開發出來,願景是把全部的重複性的工做都交給機器去作,在 css 領域就產生了 postcss。

postcss 能夠稱做爲 css 界的 babel,它的實現原理是經過 ast 去分析咱們的 css 代碼,而後將分析的結果進行處理,從而衍生出了許多種處理 css 的使用場景。

經常使用的 postcss 使用場景有:

  • 配合 stylelint 校驗 css 語法
  • 自動增長瀏覽器前綴 autoprefixer
  • 編譯 css next 的語法

更多 postcss 使用場景

CSS 模塊化迅速發展

隨着 react、vue 等基於模塊化的框架的普及使用,咱們編寫源生 css 的機會也愈來愈少。咱們經常將頁面拆分紅許多個小組件,而後像搭積木同樣將多個小組件組成最終呈現的頁面。

可是咱們知道,css 是根據類名去匹配元素的,若是有兩個組件使用了一個相同的類名,後者就會把前者的樣式給覆蓋掉,看來解決樣式命名的衝突是個大問題。

爲了解決這個問題,產生出了 CSS 模塊化的概念。

CSS 模塊化定義

  • 你是否爲 class 命名而感到苦惱?
  • 你是否有怕跟別人使用一樣 class 名而感到擔心?
  • 你是否因層級結構不清晰而感到煩躁?
  • 你是否因代碼難以複用而感到不爽?
  • 你是否由於 common.css 的龐大而感到恐懼?

你若是遇到如上問題,那麼就頗有必要使用 css 模塊化。

CSS 模塊化的實現方式

BEM 命名規範

BEM 的意思就是塊(block)、元素(element)、修飾符(modifier)。是由 Yandex 團隊提出的一種前端命名方法論。這種巧妙的命名方法讓你的 css 類對其餘開發者來講更加透明並且更有意義。

BEM 的命名規範以下:

/* 塊便是一般所說的 Web 應用開發中的組件或模塊。每一個塊在邏輯上和功能上都是相互獨立的。 */
.block {
}

/* 元素是塊中的組成部分。元素不能離開塊來使用。BEM 不推薦在元素中嵌套其餘元素。 */
.block__element {
}

/* 修飾符用來定義塊或元素的外觀和行爲。一樣的塊在應用不一樣的修飾符以後,會有不一樣的外觀 */
.block--modifier {
}
複製代碼

經過 bem 的命名方式,可讓咱們的 css 代碼層次結構清晰,經過嚴格的命名也能夠解決命名衝突的問題,但也不能徹底避免,畢竟只是一個命名約束,不按規範寫照樣能運行。

CSS Modules

CSS Modules 指的是咱們像 import js 同樣去引入咱們的 css 代碼,代碼中的每個類名都是引入對象的一個屬性,經過這種方式,便可在使用時明確指定所引用的 css 樣式。

而且 CSS Modules 在打包的時候會自動將類名轉換成 hash 值,徹底杜絕 css 類名衝突的問題。

使用方式以下:

一、定義 css 文件。

.className {
  color: green;
}
/* 編寫全局樣式 */
:global(.className) {
  color: red;
}

/* 樣式複用 */
.otherClassName {
  composes: className;
  color: yellow;
}

.otherClassName {
  composes: className from "./style.css";
}
複製代碼

二、在 js 模塊中導入 css 文件。

import styles from "./style.css";

element.innerHTML = '<div class="' + styles.className + '">';
複製代碼

三、配置 css-loader 打包。

CSS Modules 不能直接使用,而是須要進行打包,通常經過配置 css-loader 中的 modules 屬性便可完成 css modules 的配置。

// webpack.config.js
module.exports = {
  module: {
    rules: [
      {
        test: /\.css$/,
        use:{
          loader: 'css-loader',
          options: {
            modules: {
              // 自定義 hash 名稱
              localIdentName: '[path][name]__[local]--[hash:base64:5]',
            }
          }
       }
    ]
  }
};

複製代碼

四、最終打包出來的 css 類名就是由一長串 hash 值生成。

._2DHwuiHWMnKTOYG45T0x34 {
  color: red;
}

._10B-buq6_BEOTOl9urIjf8 {
  background-color: blue;
}
複製代碼

CSS In JS

CSS in JS,意思就是使用 js 語言寫 css,徹底不須要些單獨的 css 文件,全部的 css 代碼所有放在組件內部,以實現 css 的模塊化。

CSS in JS 實際上是一種編寫思想,目前已經有超過 40 多種方案的實現,最出名的是 styled-components。

使用方式以下:

import React from "react";
import styled from "styled-components";

// 建立一個帶樣式的 h1 標籤
const Title = styled.h1` font-size: 1.5em; text-align: center; color: palevioletred; `;

// 建立一個帶樣式的 section 標籤
const Wrapper = styled.section` padding: 4em; background: papayawhip; `;

// 經過屬性動態定義樣式
const Button = styled.button` background: ${props => (props.primary ? "palevioletred" : "white")}; color: ${props => (props.primary ? "white" : "palevioletred")}; font-size: 1em; margin: 1em; padding: 0.25em 1em; border: 2px solid palevioletred; border-radius: 3px; `;

// 樣式複用
const TomatoButton = styled(Button)` color: tomato; border-color: tomato; `;

<Wrapper> <Title>Hello World, this is my first styled component!</Title> <Button primary>Primary</Button> </Wrapper>;
複製代碼

能夠看到,咱們直接在 js 中編寫 css,案例中在定義源生 html 時就建立好了樣式,在使用的時候就能夠渲染出帶樣式的組件了。

除此以外,還有其餘比較出名的庫:

  • emotion
  • radium
  • glamorous

總結

最後放一張總結好的圖。

css-modules

參考連接

相關文章
相關標籤/搜索