成人国产在线小视频_日韩寡妇人妻调教在线播放_色成人www永久在线观看_2018国产精品久久_亚洲欧美高清在线30p_亚洲少妇综合一区_黄色在线播放国产_亚洲另类技巧小说校园_国产主播xx日韩_a级毛片在线免费

資訊專欄INFORMATION COLUMN

CSS Modules入門教程

suxier / 3591人閱讀

摘要:預(yù)處理器最大的好處就是可以支持模塊引入,用的方式來編寫,解決了部分混亂以及代碼冗余的問題,但是也不能完全避免。

為什么引入CSS Modules

或者可以這么說,CSS Modules為我們解決了什么痛點(diǎn)。針對(duì)以往我寫網(wǎng)頁樣式的經(jīng)驗(yàn),具體來說可以歸納為以下幾點(diǎn):

全局樣式?jīng)_突

過程是這樣的:你現(xiàn)在有兩個(gè)模塊,分別為A、B,你可能會(huì)多帶帶針對(duì)這兩個(gè)模塊編寫自己的樣式,例如a.css、b.css,看一下代碼

// A.js
import "./a.css"
const html = "

module A

" // B.js import "./b.css" const html = "

module B

"

下面是樣式:

/* a.css */
.text {
    color: red;
}

/* b.css */
.text {
    color: blue;
}

導(dǎo)入到入口APP中

// App.js
import A from "./A.js"
import B from "./B.js"

element.innerTHML = "xxx"

由于樣式是統(tǒng)一加載到入口中,因此實(shí)際上的樣式合在一起(這里暫定為mix.css)顯示順序?yàn)椋?/p>

/* mix.css */

/* a.css */
.text {
    color: red;
}

/* b.css */
.text {
    color: blue;
}

根據(jù)CSS的Layout規(guī)則,因此后面的樣式會(huì)覆蓋掉前面的樣式聲明,最終有效的就是text的顏色為blue的那條規(guī)則,這就是全局樣式覆蓋,同理,這在js中也同樣存在,因此就引入了模塊化,在js中可以用立即執(zhí)行函數(shù)表達(dá)式來隔離出不同的模塊

var moduleA = (function(document, undefined){
    // your module code
})(document)

var moduleB = (function(document, undefined){
    // your module code
})(document)

而在css中要想引入模塊化,那么就只能通過namespace來實(shí)現(xiàn),而這個(gè)又會(huì)帶來新的問題,這個(gè)下面會(huì)講到

嵌套層次過深的選擇器

為了解決全局樣式的沖突問題,就不得不引入一些特地命名namespace來區(qū)分scope,但是往往有些namespace命名得不夠清晰,就會(huì)造成要想下一個(gè)樣式不會(huì)覆蓋,就要再加一個(gè)新的namespace來進(jìn)行區(qū)分,最終可能一個(gè)元素最終的顯示樣式類似如以下:

.widget .table .row .cell .content .header .title {
  padding: 10px 20px;
  font-weight: bold;
  font-size: 2rem;
}

在上一個(gè)元素的顯示上使用了7個(gè)選擇器,總結(jié)起來會(huì)有以下問題:

  • 根據(jù)CSS選擇器的解析規(guī)則可以知道,層級(jí)越深,比較的次數(shù)也就越多。當(dāng)然在更多的情況下,可能嵌套的層次還會(huì)更深,另外,這里單單用了類選擇器,而采用類選擇器的時(shí)候,可能對(duì)整個(gè)網(wǎng)頁的渲染影響更重。
  • 增加了不必要的字節(jié)開銷
  • 語義混亂,當(dāng)文檔中出現(xiàn)過多的contenttitle以及item這些通用的類名時(shí),你可能要花上老半天才知道它們到底是用在哪個(gè)元素上
  • 可擴(kuò)展性不好,約束越多,擴(kuò)展性越差

【注】CSS的渲染規(guī)則可以參看這篇文章探究 CSS 解析原理

會(huì)帶來代碼的冗余

由于CSS不能使用類似于js的模塊化的功能,可能你在一個(gè)css文件中寫了一個(gè)公共的樣式類,而你在另外一個(gè)css也需要這樣一個(gè)樣式,這時(shí)候,你可能會(huì)多寫一次,類似于這樣的

/* a.css */

.modal {
    position: absolute;
    top: 0;
    bottom: 0;
    left: 0;
    right: 0;
    z-index: 1;
    background-color: rgba(0, 0, 0, 0.7);
}
.text {
    color: red;
}

/* b.css */
.modal {
    position: absolute;
    top: 0;
    bottom: 0;
    left: 0;
    right: 0;
    z-index: 1;
    background-color: rgba(0, 0, 0, 0.7);
}
.text {
    color: blue;
}

那么在合并成app.css的時(shí)候,就會(huì)被編寫兩遍,雖然樣式不會(huì)被影響,但是這樣實(shí)際上也是一種字節(jié)浪費(fèi),當(dāng)然,上述的這種情況完全是可以通過公用全局樣式來達(dá)到目的,但是,這種代碼重復(fù)通常是在不知情的情況下發(fā)生的。

一些解決方案

針對(duì)上述的一些問題,也有一些解決方案,具體如下:

CSS預(yù)處理器(Sass/Less等)

Sass,Less的用法這里不再贅述,如果不清楚,可以自己查閱相關(guān)資料去了解一下。

CSS預(yù)處理器最大的好處就是可以支持模塊引入,用js的方式來編寫CSS,解決了部分scope混亂以及代碼冗余的問題,但是也不能完全避免。同時(shí),也沒有解決全局樣式的沖突問題

一個(gè)SASS的的文件是這樣的:

/* app.sass */

@import "./reset"
@import "./color"
@import "./font"

可以實(shí)際上編譯之后,終究還是一個(gè)文件,因此不可避免的會(huì)出現(xiàn)沖突樣式

BEM(Block Element Modifier)

There are only two hard problems in Computer Science: cache invalidation and naming things — Phil Karlton

BEM就是為了解決命名沖突以及更好的語義化而生的。

BEM名詞解釋

  • Block:邏輯和頁面功能都獨(dú)立的頁面組件,是一個(gè)可復(fù)用單元,特點(diǎn)如下:

    • 可以隨意嵌套組合
    • 可以放在任意頁面的任何位置,不影響功能和外觀
    • 可復(fù)用,界面可以有任意多個(gè)相同Block的實(shí)例
  • Element:Block的組成部分,依賴Block存在(出了Block就不能用)
  • [可選]定義Block和Element的外觀及行為,就像HTML屬性一樣,能讓同一種Block看起來不一樣

命名規(guī)則

Block作為最小的可復(fù)用單元,任意嵌套不會(huì)影響功能和外觀,命名可以為headermenu等等



...

Element依附Block存在,沒有多帶帶的含義,命名上語義盡量接近于Block,比如title、item之類



Header

Modifier是一個(gè)元素的狀態(tài)顯示,例如active、current、selected



Header

【說明】

  • Block完全獨(dú)立,可以嵌套,一個(gè)header是一個(gè)Block,header下的搜索框也可以是一個(gè)Block
  • 不可能出現(xiàn)Block__Element-father__Element-son_Modifer這種類名的寫法,BEM只有三級(jí)
  • Modifier可以加在Block和Element上面
  • Modifier作為一個(gè)額外的類名加載Block和Element上面,只是為了改變狀態(tài),需要保留原本的class

一個(gè)完整的示例

.form { }
.form--theme-xmas { }
.form--simple { }
.form__input { }
.form__submit { }
.form__submit--disabled { }

參考鏈接:

  • get BEM
  • BEM(Block-Element-Modifier)
  • 如何看待 CSS 中 BEM 的命名方式?

BEM解決了模塊復(fù)用、全局命名沖突等問題,配合預(yù)處理CSS使用時(shí),也能得到一定程度的擴(kuò)展,但是它依然有它的問題:

  • 對(duì)于嵌套過深的層次在命名上會(huì)給需要語義化體現(xiàn)的元素造成很大的困難
  • 對(duì)于多人協(xié)作上,需要統(tǒng)一命名規(guī)范,這同樣也會(huì)造成額外的effort

CSS Modules

說了這么多,終于要到正文了

什么是CSS Modules

根據(jù)CSS Modules的repo上的話來說是這樣的:

CSS files in which all class names and animation names are scoped locally by default.

所以CSS Modules并不是一個(gè)正式的聲明或者是瀏覽器的一個(gè)實(shí)現(xiàn),而是通過構(gòu)建工具(webpack or Browserify)來使所有的class達(dá)到scope的一個(gè)過程。

CSS Modules 解決了什么問題

  • 全局命名沖突,因?yàn)镃SS Modules只關(guān)心組件本身,只要保證組件本身命名不沖突,就不會(huì)有這樣的問題,一個(gè)組件被編譯之后的類名可能是這樣的:
/* App.css */
.text {
    color: red;
}

/* 編譯之后可能是這樣的 */
.App__text___3lRY_ {
    color: red;
}

命名唯一,因此保證了全局不會(huì)沖突。

  • 模塊化

可以使用composes來引入自身模塊中的樣式以及另一個(gè)模塊的樣式:

.serif-font {
  font-family: Georgia, serif;
}

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

應(yīng)用到元素上可以這樣使用:

import type from "./type.css";

element.innerHTML = 
  `

This is a heading

`;

之后編譯出來的模板可能是這樣的:

Heading title

從另一個(gè)模塊中引入,可以這樣寫:

.element {
  composes: dark-red from "./colors.css";
  font-size: 30px;
  line-height: 1.2;
}
  • 解決嵌套層次過深的問題

因?yàn)镃SS Modules只關(guān)注與組件本身,組件本身基本都可以使用扁平的類名來寫,類似于這樣的:

.root {
  composes: box from "shared/styles/layout.css";
  border-style: dotted;
  border-color: green;
}

.text {
  composes: heading from "shared/styles/typography.css";
  font-weight: 200;
  color: green;
}

CSS Modules 怎么用

CSS Modules不局限于你使用哪個(gè)前端庫,無論是React、Vue還是Angular,只要你能使用構(gòu)建工具進(jìn)行編譯打包就可以使用。

下面我使用webpack為例,一步一步引入CSS Modules.

構(gòu)建最初始的應(yīng)用

.
├── build
│?? └── bundle.js
├── index.html
├── node_modules
├── package-lock.json
├── package.json
├── src
│?? ├── index.js
│?? └── styles
└── webpack.config.js

index.js作為程序入口,styles文件夾存放樣式文件,配合webpack.config.js作為webpack配置文件。

// index.js
var html = `

CSS Modules

` document.getElementById("container").innerHTML = html;

樣式文件:

/* global.css */
* {
    margin: 0;
    padding: 0;
}

.container {
    padding: 20px;
}

/* index.css */
.header {
    font-size: 32px;
}

.title {
    border-bottom: 1px solid #ccc;
    padding-bottom: 20px;
}

模板文件:






    
    css modules


    

全局安裝依賴,配置執(zhí)行腳本:

npm install webpack webpack-cli --save-dev

package.json

"scripts": {
    "build": "npx webpack && open index.html"
}

在控制臺(tái)執(zhí)行npm run build, 得到的結(jié)果為:

> [email protected] build /Users/yhhu/Documents/coding/css-modules-demo
> npx webpack && open index.html

Hash: 5810d2ecd760c08cc078
Version: webpack 4.17.1
Time: 78ms
Built at: 2018-08-26 15:09:31
    Asset      Size  Chunks             Chunk Names
bundle.js  3.97 KiB    main  [emitted]  main
Entrypoint main = bundle.js
[./src/index.js] 196 bytes {main} [built]

加入樣式以及l(fā)oaders

package.json中加入能夠處理css的loader

  module: {
    rules: [
      {
        test: /.js/,
        loader: "babel-loader",
        include: __dirname + "/src",
        exclude: __dirname + "/src/styles"
        },
      {
        test: /.css$/,
        use: [
          { loader: "style-loader" },
          {
            loader: "css-loader",
            options: {         
            }
          }
        ]
      }
    ]
  }

index.js中引入兩個(gè)CSS文件

// index.js
import "./styles/global.css"
import "./styles/index.css"

const html = `

CSS Modules

` document.getElementById("container").innerHTML = html;

編譯之后的執(zhí)行結(jié)果為:

在瀏覽器中顯示為:

提取公有樣式

可以看到打包之后的build目錄下只有一個(gè)bundle.js,我們現(xiàn)在要把樣式文件提取出來

./build/
└── bundle.js
  • 安裝依賴
npm install --save-dev mini-css-extract-plugin
  • 修改webpack.config.js
var MiniCssExtractPlugin = require("mini-css-extract-plugin");

modules: {
    rules: [
        // {
        //   test: /.css$/,
        //   use: [
        //      { loader: "style-loader" },
        //     {
        //      loader: "css-loader",
        //      options: {
        
        //      }
        //     }
        //   ]
        // },
        {
            test: /.css$/,
            use: [
              {
                loader: MiniCssExtractPlugin.loader,
                options: {
                  publicPath: "./build/styles"
                }
              },
              { 
                loader: "css-loader",
                options: {
                    
                }
              }
            ]
        }        
    ]
},
plugins: [
    new MiniCssExtractPlugin({
      filename: "[name].css",
      chunkFilename: "[id].css"
    })
],
  • 在模板中引入樣式文件




    


    
  • 編譯打包

可以看到有main.css生成

開啟css modules功能

默認(rèn)在css-loader中是不開啟css modules功能的,要開啟可以設(shè)置modules: true即可,更多可以參看官方css-loader使用方法修改webpack.config.js,如下:

{
    test: /.css$/,
    use: [
      {
        loader: MiniCssExtractPlugin.loader,
        options: {
          publicPath: "./build/styles"
        }
      },
      { 
        loader: "css-loader",
        options: {
            modules: true
        }
      }
    ]
}        

修改index.js文件中的引用方式:

import "./styles/global.css"
import Index from "./styles/index.css"

const html = `

CSS Modules

` document.getElementById("container").innerHTML = html;

可以看到,之前都是直接import一個(gè)css文件,而現(xiàn)在改成了導(dǎo)出一個(gè)對(duì)象的形式,我們可以把Index對(duì)象打印出來,看看具體是些什么東西:

直接對(duì)應(yīng)我們引用的方式,然后我們?cè)倏纯瓷沙鰜淼?code>main.css中具體有哪些東西:

* {
    margin: 0;
    padding: 0;
}

._2BQ9qrIFipNbLIGEytIz5Q {
    padding: 20px;
}
._3Ukt9LHwDhphmidalfey-S {
    font-size: 32px;
}

._3XpLkKvmw0hNfJyl8yU3i4 {
    border-bottom: 1px solid #ccc;
    padding-bottom: 20px;
}

合成一個(gè)文件之后,所有的類名都經(jīng)過了哈希轉(zhuǎn)換,因此確保了類名的唯一性,我們?cè)倏纯礊g覽器中inspector中的樣式應(yīng)用,如下:

事實(shí)上,container樣式我們是不需要轉(zhuǎn)換的,因?yàn)槲沂前阉潭▽懰涝诹巳萜魃?,那我們?yīng)該怎么做呢?

全局作用域

要想一個(gè)類名不需要被裝換,那么可以使用:global(className)來進(jìn)行包裝,這樣的類不會(huì)被轉(zhuǎn)換,會(huì)被原樣輸出,下面我們修改global.css

/* global.css */
* {
    margin: 0;
    padding: 0;
}

:global(.container) {
    padding: 20px;
}

我們?cè)賮砜纯?code>main.css

就可以發(fā)現(xiàn).container類沒有被轉(zhuǎn)換

定義哈希類名

CSS Modules默認(rèn)是以[hash:base64]來進(jìn)行類名轉(zhuǎn)換的,可辨識(shí)度不高,因此我們需要自定義

開啟自定義,可以使用一個(gè)配置參數(shù)localIdentName,具體配置如下:

{ 
  loader: "css-loader",
  options: {
    modules: true,
    localIdentName: "[path][name]__[local]--[hash:base64:5]"
  }
}

類名組合

如果我們實(shí)現(xiàn)類似于Sass的繼承功能,我們需要怎么做呢?CSS Modules中提供了composes關(guān)鍵字讓我們來繼承另外一個(gè)類,修改index.css如下:

.red {
    color: red;
}

.header {
    font-size: 32px;
}

.title {
    composes: red;
    border-bottom: 1px solid #ccc;
    padding-bottom: 20px;
}

我們?cè)黾恿艘粋€(gè)red的類名,在title中實(shí)現(xiàn)繼承,編譯之后的結(jié)果為:

發(fā)現(xiàn)多了一個(gè)src-styles-index__red--1ihPk的類名,正是我們上面繼承的那個(gè)類

除了在自身模塊中繼承,我們還可以繼承其他文件中的CSS規(guī)則,具體如下:

我們?cè)?code>styles文件夾下新建一個(gè)color.css

/* color.css */
.red {
    color: red;
}

.blue {
    color: blue;
}

然后在index.css文件中導(dǎo)入

/* index.css */
.red {
    color: red;
}

.header {
    font-size: 32px;
}

.title {
    color: green;
    composes: blue from "./color.css";
    composes: red;
    border-bottom: 1px solid #ccc;
    padding-bottom: 20px;
}

最終我們會(huì)發(fā)現(xiàn)文字的顏色為綠色,可見自身模塊聲明優(yōu)先級(jí)最高,如果把自身申明的color去掉,那么自身引入和從其他文件引入的相同申明又該如何顯示呢?

答案是自身引入的聲明的優(yōu)先級(jí)會(huì)比較高。

總結(jié)

至此,所有的CSS Modules用法就已經(jīng)介紹完畢了,至于后續(xù)的還有如何應(yīng)用于React、Vue以及Angular中,相信掌握了上面的內(nèi)容之后就可以知道怎么寫了,如何與預(yù)處理器一起使用相信問題也不大。

最后,本文代碼倉庫庫為:https://github.com/Rynxiao/css-modules-demo

參考鏈接

  • CSS Modules?—?Solving the challenges of CSS at scale
  • github repo
  • What are CSS Modules and why do we need them?
  • Getting Started with CSS Modules
  • Get BEM
  • CSS Modules 用法教程
  • CSS Modules使用詳解
  • 探究 CSS 解析原理

文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請(qǐng)注明本文地址:http://systransis.cn/yun/1878.html

相關(guān)文章

  • CSS module 入門

    摘要:示例庫通過記錄來查看定制類名默認(rèn)的哈希算法是,從前面我們可以發(fā)現(xiàn)被編譯成了這樣的字符串。與上面不加等價(jià)顯式的局部作用域語法通過示例庫的記錄來查看下的樣式復(fù)用對(duì)于樣式復(fù)用,提供了組合的方式來處理。 showImg(https://segmentfault.com/img/bV9WfX?w=800&h=274);前端發(fā)展越來越快,這應(yīng)該是每個(gè)前端開發(fā)者的切身感受,但是CSS 是前端領(lǐng)域中進(jìn)...

    warnerwu 評(píng)論0 收藏0
  • 2017-09-03 前端日?qǐng)?bào)

    摘要:前端日?qǐng)?bào)精選精讀引擎特性帶來的的性能變化中的藝術(shù)譯你是如何拆分組件的高級(jí)技巧如何遍歷中對(duì)象屬性一個(gè)可視化并且能快速生成模擬數(shù)據(jù)的持久化服務(wù)中文第期中的執(zhí)行上下文和調(diào)用棧是什么譯誰更適合前端開發(fā)掘金實(shí)戰(zhàn)桌面計(jì)算器應(yīng)用我們?nèi)找蛊谂蔚? 2017-09-03 前端日?qǐng)?bào) 精選 精讀《V8 引擎特性帶來的的 JS 性能變化》CSS中的藝術(shù)[譯] 你是如何拆分組件的?JS高級(jí)技巧如何遍歷JavaSc...

    岳光 評(píng)論0 收藏0
  • CSS Modules實(shí)踐

    摘要:能最大化地結(jié)合現(xiàn)有生態(tài)預(yù)處理器后處理器等和模塊化能力,幾乎零學(xué)習(xí)成本。編碼相關(guān)的所有樣式上例中打印的結(jié)果是注意到是按照自動(dòng)生成的名。實(shí)踐手動(dòng)引用渲染結(jié)果使用可以實(shí)現(xiàn)使用屬性自動(dòng)加載模塊。 文章同步于Github Pines-Cheng/blog 隨著前端這幾年的風(fēng)生水起,CSS作為前端的三劍客之一,各種技術(shù)方案也是層出不窮。從CSS prepocessor(SASS、LESS、Styl...

    hankkin 評(píng)論0 收藏0
  • [譯]教程:如何使用Rollup打包樣式文件并添加LiveReload

    摘要:通過這個(gè)教程學(xué)習(xí)如何使用打包工具配合來取代或處理樣式文件。使用這個(gè)命令安裝插件更新。如果你沒有項(xiàng)目的副本,你可以通過這條命令克隆在結(jié)束這個(gè)狀態(tài)下的項(xiàng)目為添加監(jiān)聽插件。在代碼塊內(nèi),添加如下內(nèi)容簡(jiǎn)單起見我省略了文件的大部分內(nèi)容 通過這個(gè)教程學(xué)習(xí)如何使用JavaScript打包工具Rollup配合PostCSS來取代Grunt或Gulp處理樣式文件。 上一篇文章中,我們完成了使用Rollup...

    garfileo 評(píng)論0 收藏0
  • webpack中的那些坑

    摘要:之前在簡(jiǎn)書上看到一個(gè)入門入門,看這篇就夠了,講得確實(shí)很清楚,但是因?yàn)椴┲饔玫氖堑陌姹荆同F(xiàn)在普遍默認(rèn)安裝的版本有一些細(xì)節(jié)上的差距,所以實(shí)際使用的時(shí)候就會(huì)遇到一些坑,對(duì)于想入門的小白如我,造成了不小的困擾。 之前在簡(jiǎn)書上看到一個(gè)webpack入門(入門Webpack,看這篇就夠了),講得確實(shí)很清楚,但是因?yàn)椴┲饔玫氖?.x的版本,和現(xiàn)在普遍默認(rèn)安裝的2.x版本有一些細(xì)節(jié)上的差距,所以實(shí)際...

    marek 評(píng)論0 收藏0

發(fā)表評(píng)論

0條評(píng)論

最新活動(dòng)
閱讀需要支付1元查看
<