【轉】理解CSS模塊化

原文連接: https://www.sitepoint.com/und...css

在瞬息萬變的前端開發世界中,很難找到一個真正有意義的概念,而且將其清晰明瞭的向廣大人民羣衆普及。前端

把目光投向CSS,一個重大轉折就是CSS預處理器的出現(在工具方面來看),其中, Sass應該是最爲著名的一個。此外,還有 PostCSS,它和Sass略有不一樣,可是異曲同工——都是用瀏覽器不能解析的語法編寫,而且最終編譯成瀏覽器可以理解的語法。webpack

如今,又有一位新的成員出現了,它就是CSS模塊。本文就將介紹CSS模塊化的諸多優勢,以及如何編寫模塊化的CSS。web

什麼是CSS模塊
首先,讓咱們從官方文檔入手:npm

A CSS Module is a CSS file in which all class names and animation names are scoped locally by default. CSS模塊就是全部的類名都只有局部做用域的CSS文件。json

事實稍微有一些複雜。因爲類名須要默認具備局部做用域,這就涉及到一些初始設置、一個編譯過程,以及其餘一些難以琢磨的東西。瀏覽器

可是最終,咱們會爲CSS模塊化帶來的好處而開心:CCS模塊將做用域限制於組件中,從而避免了全局做用域的問題。咱們不再用操心爲組件尋找一個好的命名了,由於編譯過程已經幫你完成了這個任務。app

它是如何工做的
CSS模塊須要在構建步驟進行管道化,這也就是說,它不是自動驅動的。它能夠當作是webpack 或 Browserify的一個插件。其基本工做方式是:當你在一個JavaScript模塊中導入一個CSS文件時(例如,在一個 React 組件中),CSS模塊將會定義一個對象,將文件中類的名字動態的映射爲JavaScript做用域中可使用的字符串。舉個具體的例子:模塊化

以下是一個簡單的CSS文件。其中,.base類名不須要是工程中惟一的,由於它將不會是真正被解析的類名。它能夠當作是在JavaScript模塊中使用的類在樣式表中的別名。工具

.base {
  color: deeppink;
  max-width: 42em;
  margin: 0 auto;
}

下面是該CSS類在JavaScript組件中的使用方式:

import styles from './styles.css';

element.innerHTML = `<div class="${styles.base}">
  CSS Modules are fun.
</div>`;

最終,它將生成下面這個東西(當使用webpack的默認步驟時):

`<div class="_20WEds96_Ee1ra54-24ePy">CSS Modules are fun.</div>`
._20WEds96_Ee1ra54-24ePy {
  color: deeppink;
  max-width: 42em;
  margin: 0 auto;
}

固然,生成的類名能夠經過配置,使得它的長度更短或者遵循一些特定的模式。固然了,這些最終都不重要(雖然短的類名意味着更短的樣式表),重點在於這些類名是動態生成的、惟一的且和正確的樣式表一一對應的。

一些須要注意的地方
這就是CSS模塊工做的方式了。這時,你可能會想,「這究竟是個什麼玩意兒,我甚至。。。」。OK,停下!我知道你想說什麼。如今就讓我一一解答你可能有的疑慮。

這看起來太醜了

確實如此。可是類名並不要求必定要長的好看對不對?只要能夠將樣式正確的應用於元素就能夠了嘛。而CSS模塊化方法完成的很是好,因此我以爲,這不是一個問題。

這很是難debug啊

因爲須要有一個編譯的步驟,因此直接debug是很是困難的。其實,像Sass直接debug也是至關不容易的,因此咱們纔有了 sourcemaps。對於CSS模塊,咱們也能夠設置sourcemap。

其實,我還想說的是,雖然在模塊中,類的名字是自動生成而不可預知的,可是對於模塊來講,它仍是比樣式表更容易debug的。只要你知道當前在開發者工具中查看的樣式屬於哪一個模塊,在相應的樣式表中也是很容易定位。

這使得樣式不容易複用啦!

這句話既對也不對。一方面來講,確實如此。但這是由於模塊將CSS樣式和組件相綁定,從而不會發生全局樣式的衝突。這實際上是一件好事,我相信你也會贊成的對不對。

另外一方面,要定義全局樣式也是能夠的,只要使用:global()就行了。好比,做者須要保留的全局輔助樣式。

:global(.clearfix::after) {
  content: '';
  clear: both;
  display: table;
}

CSS模塊還能夠從其餘模塊中繼承樣式,這和Sass中的@extend方法實際上是同樣的。它不會拷貝樣式,只是將選擇器鏈接到繼承的樣式中。

.base {
  composes: appearance from '../AnoherModule/styles.css';
}

它須要webpack,Browserify或者其餘工具!

這和Sass須要將.scss文件編譯成CSS文件,PostCSS須要將樣式表處理成瀏覽器可以識別的樣式實際上是同樣的。不管如何,都須要一個構建步驟。

咱們究竟爲何要討論這個東西?

其實,我甚至不肯定CSS模塊在將來到底會不會繼續存在,不過,我肯定這是一種編寫樣式的正確方式。試想,在拆分紅許多細小組件的龐大站點中,卻擁有一個臃腫的全局樣式表,這確定是不合適的。

CSS統一的名空間使得它既強大又脆弱。而CSS模塊化或者將來延續這個思想的其餘工具能夠在支持樣式複用的同時,避免命名衝突,這是一個共贏的選擇。

入門
如前面所說的,你須要有webpack或者Browserify來實現CSS模塊化。

Webpack

先從webpack版本的模塊化開始。在webpack.config.js中,加上以下配置,使得webpack將CSS文件做爲CSS模塊來看待:

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

這時,它將把樣式注入到頁面中的``元素中。這可能不是咱們想要的,使用extract text plugin for webpack,咱們能夠很方便的抽取出樣式表:

{
  test: /\.css$/,
  loader: ExtractTextPlugin.extract('style-loader', 'css-loader?modules')
}

對於webpack,要講的就是這麼多了。

Browserify

我只在命令行中用過Browserify,因此我猜使用起來會更復雜一些。在package.json文件中,加入 npm script :

{
  "scripts": {
    "build": "browserify -p [ css-modulesify -o dist/main.css ] -o dist/index.js src/index.js"
  }
}

這條命令告訴Browserify運行src/index.js,返回dist/index.js,而且使用 css-modulesify將樣式表編譯至dist/main.css。若是你想再加上Autoprefixer,那麼命令能夠寫成這樣:

{
  "scripts": {
    "build": "browserify -p [ css-modulesify --after autoprefixer -o dist/main.css ] -o dist/index.js src/index.js"
  }
}

如你所見,使用--after選項能夠在編譯完成樣式表時候,繼續對它進行處理。

總結
從今天看來,CSS模塊化系統和生態確實有些原始了,從Browserify中的配置就能看出來。不過,我確信CSS模塊化將變得更好,而且愈來愈多的人將意識到無論對小項目仍是大項目來講,這都是一個很好的方法。

我認爲CSS模塊化背後的思想是正確的。固然,我不是說這個庫就是最佳解決方案,可是,它確實包含了一些CSS應該採用的寫法:模塊化、做用域隔離、同時支持複用。

相關文章
相關標籤/搜索