最近年末,抽出一點時間總結了一下 css 的模塊化。css
原文地址,歡迎 Star 和 訂閱 個人博客。html
咱們在書寫 css 的時候其實經歷瞭如下幾個階段:前端
在咱們最初學習寫頁面的時候,你們都學過怎麼去寫 css,也就如下幾種狀況:vue
咱們在不斷摸索中,逐漸造成了以編寫內嵌樣式和外部樣式爲主要的編寫習慣。react
讀到這裏你們確定有所疑問,爲何不建議使用行內樣式?webpack
使用行內樣式的缺點git
- 樣式不能複用。
- 樣式權重過高,樣式很差覆蓋。
- 表現層與結構層沒有分離。
- 不能進行緩存,影響加載效率。
而後咱們繼續剖析一下,爲何不建議使用導入樣式?github
經測試,在 css 中使用 @import 會有如下兩種狀況:web
一、在 IE6-8 下,@import 聲明指向的樣式表並不會與頁面其餘資源併發加載,而是等頁面全部資源加載完成後纔開始下載。前端工程化
二、若是在 link 標籤中去 @import 其餘 css,頁面會等到全部資源加載完成後,纔開始解析 link 標籤中 @import 的 css。
使用導入樣式的缺點
- 導入樣式,只能放在 style 標籤的第一行,放其餘行則會無效。
- @import 聲明的樣式表不能充分利用瀏覽器併發請求資源的行爲,其加載行爲每每會延後觸發或被其餘資源加載掛起。
- 因爲 @import 樣式表的延後加載,可能會致使頁面樣式閃爍。
隨着時間的不斷髮展,咱們逐漸發現,編寫源生的 css 其實並不友好,例如:源生的 css 不支持變量,不支持嵌套,不支持父選擇器等等,這些種種問題,催生出了像 sass/less 這樣的預處理器。
預處理器主要是強化了 css 的語法,彌補了上文說了這些問題,但本質上,打包出來的結果和源生的 css 都是同樣的,只是對開發者友好,寫起來更順滑。
隨着前端工程化的不斷髮展,愈來愈多的工具被前端大佬們開發出來,願景是把全部的重複性的工做都交給機器去作,在 css 領域就產生了 postcss。
postcss 能夠稱做爲 css 界的 babel,它的實現原理是經過 ast 去分析咱們的 css 代碼,而後將分析的結果進行處理,從而衍生出了許多種處理 css 的使用場景。
經常使用的 postcss 使用場景有:
隨着 react、vue 等基於模塊化的框架的普及使用,咱們編寫源生 css 的機會也愈來愈少。咱們經常將頁面拆分紅許多個小組件,而後像搭積木同樣將多個小組件組成最終呈現的頁面。
可是咱們知道,css 是根據類名去匹配元素的,若是有兩個組件使用了一個相同的類名,後者就會把前者的樣式給覆蓋掉,看來解決樣式命名的衝突是個大問題。
爲了解決這個問題,產生出了 CSS 模塊化的概念。
你若是遇到如上問題,那麼就頗有必要使用 css 模塊化。
BEM 的意思就是塊(block)、元素(element)、修飾符(modifier)。是由 Yandex 團隊提出的一種前端命名方法論。這種巧妙的命名方法讓你的 css 類對其餘開發者來講更加透明並且更有意義。
BEM 的命名規範以下:
/* 塊便是一般所說的 Web 應用開發中的組件或模塊。每一個塊在邏輯上和功能上都是相互獨立的。 */
.block {
}
/* 元素是塊中的組成部分。元素不能離開塊來使用。BEM 不推薦在元素中嵌套其餘元素。 */
.block__element {
}
/* 修飾符用來定義塊或元素的外觀和行爲。一樣的塊在應用不一樣的修飾符以後,會有不一樣的外觀 */
.block--modifier {
}
複製代碼
經過 bem 的命名方式,可讓咱們的 css 代碼層次結構清晰,經過嚴格的命名也能夠解決命名衝突的問題,但也不能徹底避免,畢竟只是一個命名約束,不按規範寫照樣能運行。
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,意思就是使用 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 時就建立好了樣式,在使用的時候就能夠渲染出帶樣式的組件了。
除此以外,還有其餘比較出名的庫:
最後放一張總結好的圖。