CSS Modules入門Ⅰ:它是什麼?為什麼要使用它?

原文鏈接:What are CSS Modules and why do we need them?

作者:ROBIN RENDLE

最近我對CSS模塊特別感興趣,要是你以前還從未聽說過CSS Modules,那麼這個系列就是專門寫給你的。首先我們會介紹一下CSS Modules是什麼以及為什麼要將CSS模塊化,之後大概介紹一下如何應用CSS Modules。最後如果你想進一步提升自己,可以閱讀第三部分介紹的如何在React環境下使用CSS Modules。

  • 第一部分:什麼是CSS Modules?為什麼要使用它?
  • 第二部分:如何上手CSS Modules
  • 第三部分:在React中使用CSS Modules

什麼是CSS Modules?

根據CSS Modules在Gihub上的項目,它被解釋為:

所有的類名和動畫名稱默認都有各自的作用域的CSS文件。

所以CSS Modules既不是官方標準,也不是瀏覽器的特性,而是在構建步驟(例如使用Webpack或Browserify)中對CSS類名和選擇器限定作用域的一種方式(類似於命名空間)。

我們還是先看一個具體的例子來解釋清楚它到底是什麼,以及為什麼要使用CSS Modules吧。我們通常給HTML加一個CSS的類名來控制它的樣式:

<h1 class="title">An example heading</h1>

CSS樣式像下面這樣:

.title { background-color: red;}

只要把CSS文件載入到HTML文件中,這裡的<h1>標籤背景就會被設置成紅色。我們不需要對HTML或CSS做什麼特殊的處理,瀏覽器本來就支持這種最基本的文件類型。

而CSS Modules的使用方式就不一樣了,我們需要把所有的標籤寫到JS文件里。下面是一個簡單的示例:

import styles from "./styles.css";element.innerHTML = `<h1 class="${styles.title}"> An example heading </h1>`;

在JS中你可以通過類似styles.title的方式訪問CSS文件中的.title類。然後在構建過程中,我們的構建工具會搜索我們用import語句載入的名為styles.css的文件,之後把源文件解析成新的HTML和CSS文件,類名會被特定的格式替換:

HTML

<h1 class="_styles__title_309571057"> An example heading</h1>

CSS

._styles__title_309571057 { background-color: red;}

類屬型的.title完全被新生成的命名替換掉了,CSS的源文件也不會被載入。

在 Hugo Giraudel 的教程 里也提到:

在使用CSS模塊時,類名是動態生成的,唯一的,並準確對應到源文件中的各個類的樣式。

這也是實現樣式作用域的原理。它們被限定在特定的模板里。例如我們在buttons.js里引入buttons.css文件,並使用.btn的樣式,在其他諸如forms.js里是不會被.btn影響的,除非它也引入了buttons.css.

可我們是出於什麼目的把CSS和HTML文件搞得這麼零碎呢?我們為什麼要使用CSS模塊呢?

為什麼要使用CSS Modules?

通過CSS Modules,我們可以保證單個組件的所有樣式:

  1. 集中在同一個地方
  2. 只應用於該組件

另外,

import buttons from "./buttons.css";import padding from "./padding.css";element.innerHTML = `<div class="${buttons.red} ${padding.large}">`;

通過這樣的方式可以解決CSS全局作用域的問題。

你一定經歷過著急著趕工想要儘快寫完CSS,而根本沒有考慮過你的代碼會造成什麼不良影響吧。

你也一定干過在某個樣式文件的結尾加上隨意命名的亂七八糟的樣式之類吧。

你肯定也見過那些你不知道有什麼效果,甚至到底有沒有被使用的樣式吧。

你難道不想安全地寫出不影響其他樣式的CSS么?擔心樣式是獨立或者依賴別的什麼東西么?或者可能會覆蓋別的地方的樣式?

諸如此類的問題都足夠讓人頭疼了。而且隨著項目的擴張,會越來越令人絕望。

但使用CSS Modules就可以避免這些問題。除非你在某個模塊中載入一個CSS樣式,其他情況下這個樣式都不會影響別的HTML.

composes關鍵詞屬性

假如我們有如下一個名為type.css的樣式文件:

.serif-font { font-family: Georgia, serif;}.display { composes: serif-font; font-size: 30px; line-height: 35px;}

之後我們在模板里聲明其中的第二個屬性:

import type from "./type.css";element.innerHTML = `<h1 class="${type.display}"> This is a heading </h1>`;

生成的結果大概是這個樣子:

<h1 class="_type__display_0980340 _type__serif_404840"> Heading title</h1>

樣式中的兩個屬性通過composes關鍵字都載入到了該元素上,實現了類似Sass中@extend的功能。

我們甚至可以通過composes繼承其他文件中的樣式:

.element { composes: dark-red from "./colors.css"; font-size: 30px; line-height: 1.2;}

BEM代碼規範不再是必須的

在編寫CSS模塊時我們不再需要遵守BEM規範,有這麼兩個原因:

  1. 簡化語法——在CSS Modules中通過類似type.display的表達已經能夠很好地被理解了。比起某些BEM中例如.font-size__serif--large這樣的命名要更清晰。
  2. 作用域——比如我們的一個CSS中的.big是用來描述文字大小的,另一個CSS中的.big是用來增加間距的。通過使用CSS Modules,我們在能夠隨意使用相同命名類的同時,更不用擔心它們之間起衝突。即使是在同一個文件中引入這兩個CSS,最後生成的結果也會把兩個樣式區別開來。

這僅僅是使用CSS Modules的一點點好處而已。

如果你想了解更多CSS Modules的優點,可以看Glen Madden寫的這篇文章。

在下一篇中,我們將會討論如何在項目中通過Webpack來使用CSS Modules,通過使用一些ES6的最新特性以及具體的例子來學習。


推薦閱讀:

通信技術:SSE設計方案(一)--- 前端Server-Sent Events概念講解和基礎類庫完善發布
項目代碼調試:提問前要做的六個步驟
帶你了解前端開發
精讀《如何安全地使用 React context》

TAG:CSS | 前端开发 | 前端入门 |