Postcss 簡(jiǎn)明教程 及 css module

在前端開發(fā)中一直有個(gè)原則蒲列,叫做"關(guān)注點(diǎn)分離",意思就是各種技術(shù)只負(fù)責(zé)自己的領(lǐng)域晴氨,不要混合在一起茄茁,形成耦合魂贬,這種原則比較直觀的體現(xiàn)就是不要寫"行內(nèi)樣式"(inline style)和"行內(nèi)腳本"(inline script),HTML裙顽、CSS随橘、JavaScript各干各的事,避免混用(此處參考CSS in JS 簡(jiǎn)介

現(xiàn)在前端在進(jìn)行開發(fā)時(shí)锦庸,基本都被各種框架覆蓋,新起一個(gè)項(xiàng)目蒲祈,第一步都是技術(shù)選型甘萧。看看是用 React梆掸、還是用 Vue扬卷,然后再配套的去選擇相關(guān)技術(shù)棧,以及相應(yīng)的框架酸钦。這是技術(shù)的進(jìn)度怪得,讓開發(fā)人員能比較關(guān)注業(yè)務(wù)邏輯的展開,但另一方面也可以認(rèn)為這是一種枷鎖。徒恋。蚕断。

由于框架的使用,使我們之前的關(guān)注點(diǎn)分離變的策略入挣,現(xiàn)在其實(shí)都是在 js 中進(jìn)行亿乳。HTML 以 虛擬DOM 的形式存在其中,css 通常是以 import 的形式載入径筏,最終通過(guò) webpack 之類的工具葛假,再導(dǎo)出成一個(gè)獨(dú)立的樣式文件。

相比 HTML滋恬,框架對(duì) CSS 都沒進(jìn)行什么特殊處理聊训,也沒有形成類似 JSX 的解決方案,不過(guò)這其中倒是有一個(gè)比較有意思的解決方案:css-in-js(不過(guò)在 js 中寫 css恢氯,怎么都感覺有些別扭)带斑。

另外 css 本身編程能力薄弱,社區(qū)也形成各種方案來(lái)提升 css 編程能力酿雪。相比其他方案遏暴,我感覺 Postcss 更為優(yōu)雅,所以這里特別介紹下

目前是基于 postcss 7.0.31 版本

基本概念

  • Postcss是一個(gè)用 js 插件轉(zhuǎn)換成 css 的工具
  • Postcss 不是預(yù)處理器

預(yù)處理器是指對(duì) css 能力增強(qiáng)的功能指黎,添加一些一些本身不是css的功能(比如嵌套朋凉、變量),通過(guò)處理后能轉(zhuǎn)成普通的CSS醋安,

  • Postcss 不是后處理器

通過(guò)一些規(guī)則把已有的css進(jìn)行完善杂彭,比如添加瀏覽器前綴

  • Postcss 是作為一個(gè)平臺(tái)的存在,利用 Postcss 提供的插件可以組合各種不同模塊吓揪,來(lái)構(gòu)建更為復(fù)雜的功能

Demo

此處沒有使用vue或react的腳手架亲怠,為了演示完整功能,構(gòu)建了一個(gè)基于Vue的開發(fā)環(huán)境柠辞,并演示加載樣式和提取

  • 任意目錄 npm init -y

使用這種方式团秽,項(xiàng)目的名詞一定不要和某些庫(kù)的名詞沖突,比如叫webpack叭首,postcss习勤,如果叫這個(gè)名詞安裝相關(guān)庫(kù)時(shí)就會(huì)報(bào)ENOSELF的錯(cuò)誤

  • 安裝 相關(guān)依賴

npm i --save-dev webpack webpack-cli webpack-dev-server html-webpack-plugin postcss postcss-loader mini-css-extract-plugin css-loader style-loader @babel/cli @babel/core @babel/preset-env vue-loader vue-template-compiler

npm i --save vue

* css-loader 是可以在頁(yè)面中使用 import 引入 css 的能力
* style-loader 是把 css 代碼生成 style 標(biāo)簽,放到 head 標(biāo)簽中
* mini-css-extract-plugin 提取css用的插件

其他包不在本文討論范圍焙格,故不介紹

  • 新建兩個(gè)文件夾 src 图毕、dist,以及 babel.config.js眷唉、 webpack.config.js 和其他相關(guān)文件
/// babel.config.js
const presets = [["@babel/env"]];

module.exports = {
    presets
}
...
/// webpack.config.js
const HtmlWebpackPlugin = require('html-webpack-plugin');
const VueLoaderPlugin = require('vue-loader/lib/plugin');

module.exports = {
    entry: './src/index.js',
    resolve: {
        extensions: ['.js', '.vue']
    },
    output: {
        filename: '[name].js',
        publicPath: '/'
    },
    mode: 'development',
    module: {
        rules: [
            {test: /\.js$/, use: 'babel-loader', exclude: /node_modules/},
            {test: /\.vue$/, use: 'vue-loader', exclude: /node_modules/},
            {test: /\.css/, use: ['style-loader', 'css-loader']}
        ]
    },
    devServer: {
        port: '8111'
    },
    plugins: [
        new HtmlWebpackPlugin({
            template: './src/tpl/index.html'
        }),
        new VueLoaderPlugin()
    ]
}
...
/// 假定有個(gè) app.vue 按如上設(shè)置
import '../style/app.css';

這時(shí)就可以通過(guò) import 方式把樣式文件導(dǎo)入到頁(yè)面中予颤,因?yàn)榇藭r(shí)用的是 style-loader 囤官,樣式會(huì)寫入到 <head> 下的 <style> 標(biāo)簽中

  • 如不喜歡那種在把樣式一股腦掉到 <head> 的方式,可使用 mini-css-extract-plugin 蛤虐,這會(huì)把相關(guān)樣式拆分成一個(gè)個(gè)獨(dú)立的文件
/// webpack.config.js
const MiniCssExtractPlugin = require("mini-css-extract-plugin");
...
{test: /\.css/, use: [MiniCssExtractPlugin.loader, 'css-loader']} // 替換 style-loader
...
plugins: [
    ...
    new MiniCssExtractPlugin({
    filename: "[name].css",
    chunkFilename: "[id].css"
  })
]
  • import 多個(gè)文件党饮,按目前的設(shè)置,會(huì)合并和一個(gè)樣式文件導(dǎo)出笆焰,不過(guò)這些文件中的內(nèi)容劫谅,只是簡(jiǎn)單的合并在一起,而且也沒編程思想在其中嚷掠,完全依賴樣式編寫人員控制每個(gè)樣式文件的內(nèi)容
/// app.css
.info {
    font-size: 24px;
}
...
/// color.css
.info {
    color: red;
}
...
/// app.vue
import '../style/app.css';
import '../style/color.css';
...
/// 合并出的樣式文件如下
.info {
    font-size: 24px;
}
.info {
    color: red;
}

編程化

通過(guò) .pcss 引入樣式文件

.pcss 是 Postcss 的專用格式文件

  • 安裝 postcss-import捏检,使在 .pcss 文件可以使用 @import 引入樣式文件

npm i --save-dev postcss-import

需要先添加一個(gè)對(duì) Postcss 的運(yùn)行配置文件,可以叫 .postcssrc.jspostcss.config.js

// 暫時(shí)沒有其他配置不皆,可以把留空
module.exports = {
    plugins: []
}

postcss.config.js 除了 plugins 還具有如下參數(shù):

  • syntax: 提供語(yǔ)法分析器和字符串化器的對(duì)象
  • parser: 特殊的語(yǔ)法解析器(例如贯城,SCSS)
  • stringifier: 特殊語(yǔ)法輸出生成器(例如Midas)
  • map: 對(duì)map文件的設(shè)置
  • from: 輸入文件名
  • to: 輸出文件名

不過(guò)常用的就是 plugins (定義使用的插件)

/// 在webpack.config.js中做如下修改
{test: /\.pcss$/, use: [
    MiniCssExtractPlugin.loader,
    "css-loader",
    "postcss-loader"
]},
...
/// mian.pcss
@import './app.css';
@import './color.css';
...
/// app.vue 引入 main.pcss
import './main.pcss';

PostCss 的編程能力,是通過(guò)各種插件實(shí)現(xiàn)的霹娄,可以自己編寫能犯,或者直接使用社區(qū)現(xiàn)有插件,插件在 Postcss 的配置文件中設(shè)置使用參數(shù)

autoprefixer

這應(yīng)該是postcss中使用最為廣泛的插件了犬耻,自動(dòng)識(shí)別設(shè)定的瀏覽器兼容范圍踩晶,添加瀏覽器樣式前綴

npm i --save-dev autoprefixer

/// postcss.config.js
let postcssConfig = {};
postcssConfig.autoprefixer = {
    browsers: ['> 1%', 'ff 3']
}

module.exports = {
    plugins: postcssConfig
}
  • 修改main.pcss內(nèi)容如下
b {
    border-radius:5px;
}

編譯運(yùn)行后結(jié)果為

b {
       -moz-border-radius:5px;
            border-radius:5px;
}

autoprefixer 的參數(shù),使用默認(rèn)配置即可枕磁。這里只說(shuō) browsers 參數(shù)的設(shè)定渡蜻,因?yàn)檫@關(guān)系到最終添加前綴的內(nèi)容。

browsers 是利用 browserslist 功能來(lái)決定是否需要添加某些瀏覽器前綴计济,在browserslist的文檔里我們可以找到詳細(xì)設(shè)定茸苇,可以設(shè)定針對(duì)瀏覽器、國(guó)家沦寂、指定平臺(tái)学密、年份做設(shè)置

> 5%
cover 99.5%
> 5% in US
node 10 and node 10.4
since 2015
ie 6-8
not ie <= 8

下面列舉下在項(xiàng)目中最有可能碰到的瀏覽器

  • Android: Android webview瀏覽器
  • iOS: ios的Safari瀏覽器
  • Chrome: 谷歌瀏覽器
  • ChromeAndroid: 谷歌瀏覽器安卓版
  • Edge: 微軟的Edge瀏覽器
  • ie: ie瀏覽器
  • Safari: Safari桌面瀏覽器
  • ff: firefox瀏覽器
  • and_ff: firefox安卓瀏覽器
  • and_qq: QQ瀏覽器安卓版
  • and_uc: UC瀏覽器安卓版

browsers 接收的是一個(gè)數(shù)組,所以可以像例子中那樣分開設(shè)置传藏,下面的話的意思就是為了適配 安卓2.3腻暮,ios3.2,Safari3.1毯侦,IE10 瀏覽器要添加相關(guān)前綴

'> 0%','Android 2.3','iOS 3.2','Safari 3.1','IE 10'

> 0% 是指當(dāng)你不想像上面設(shè)置那么繁瑣的指定瀏覽器時(shí)西壮,可以直接指定個(gè)大概,就是我要支持市面上多少多少比例的瀏覽器叫惊,這個(gè)數(shù)字前面可以添加普通的運(yùn)算符 >塘装、>=审丘、<<=

前綴修飾符 not 表示不在某個(gè)范圍中砚哗,還可以使用 cover extendssince 進(jìn)行更細(xì)化的設(shè)置,包括道指定從哪年開始的什么版本蔗坯。

圓角功能是 ff4 才加的功能康震,我們指定適配某個(gè)瀏覽器版本,這時(shí)就會(huì)發(fā)現(xiàn)運(yùn)行后的樣式一樣會(huì)有ff的私有前綴宾濒,所以一般我們結(jié)合瀏覽器覆蓋范圍腿短,再加上對(duì)特定瀏覽器的排除就能完成相關(guān)設(shè)置

/// 如此設(shè)定后,生成的樣式就不會(huì)有針對(duì) 火狐瀏覽器 的前綴
  browsers: ['> 1%', 'ff > 4']

有一點(diǎn)需要注意的绘梦,設(shè)置范圍時(shí)需要指定范圍橘忱,不能直接設(shè)置ff或者not ff,這時(shí)編譯會(huì)報(bào)錯(cuò)卸奉,你需要明確指明版本才可以

在 package.json 中設(shè)置 browserslist

由于還會(huì)有其他插件(比如 babel )需要針對(duì)瀏覽器設(shè)置兼容情況钝诚,所以針對(duì)瀏覽器的范圍設(shè)定,一般會(huì)建議加上 package.json 中榄棵。
在其中凝颇,設(shè)置 "browserslist": ["> 1%", "ff > 4"](package.json 中設(shè)定的優(yōu)先級(jí)低于插件的設(shè)置)

postcss-preset-env

這個(gè)插件允許開發(fā)人員在當(dāng)前項(xiàng)目中使用 css 將來(lái)版本可能會(huì)加入的新特性,這個(gè)就非常類似于寫 ES6 的代碼疹鳄,但是使用 babel 轉(zhuǎn)成 ES5 的代碼拧略。

這個(gè)插件中包含了autoprefixer

另外一個(gè)類似的插件,postcss-cssnext 已經(jīng)不再維護(hù)

npm i --save-dev postcss-preset-env

// 新增
const postcssPresetEnv = require('postcss-preset-env');

module.exports = {
  plugins: [
  postcssPresetEnv({ 
    stage: 2
    // browsers: 'last 2 versions' // 這個(gè)插件包含 autoprefixer 的功能瘪弓,可以在配置中進(jìn)行瀏覽器的相關(guān)設(shè)定
  })
  ]
}

插件參數(shù)說(shuō)明

下面根據(jù)官方的文檔介紹相關(guān)設(shè)置參數(shù):

  • stage: 根據(jù)現(xiàn)行web標(biāo)準(zhǔn)的進(jìn)程(主要就是 w3c 組織認(rèn)定的標(biāo)準(zhǔn)垫蛆,所以這個(gè)插件中具備的功能都是未來(lái)很有可能直接加到 css 標(biāo)準(zhǔn)中的內(nèi)容)來(lái)決定某些 css 功能需不需要通過(guò)墊片的方式添加,可以設(shè)置 0~4 的任意數(shù)字杠茬,如果沒有設(shè)置這個(gè)值月褥,這個(gè)值默認(rèn)為 2

    • 0: 這個(gè)階段處在 非官方草案或編輯草案階段,很有可能會(huì)被刪除
    • 1: 這個(gè)階段處于 實(shí)驗(yàn)階段瓢喉,有可能會(huì)被設(shè)置為標(biāo)準(zhǔn)
    • 2: 這個(gè)階段處于 待定階段宁赤,這也是插件默認(rèn)的數(shù)值,處于這個(gè)階段的功能栓票,基本可以認(rèn)為會(huì)被加到未來(lái)的標(biāo)準(zhǔn)中
    • 3: 這個(gè)階段處于 穩(wěn)定階段决左,基本上已經(jīng)有瀏覽器廠商實(shí)現(xiàn)了,可以直接使用
    • 4: 這個(gè)階段處于 標(biāo)準(zhǔn)階段
  • features: 針對(duì)特定css功能進(jìn)行單獨(dú)設(shè)置走贪,比如設(shè)置了 stage3佛猛,可以通過(guò)這個(gè)參數(shù)來(lái)特定使用還處于 stage2 的功能

postcssPresetEnv({
  /* 使用stage為3的標(biāo)準(zhǔn),同時(shí)允許嵌套規(guī)則(嵌套是stage 0的標(biāo)準(zhǔn)) */
  stage: 3,
  features: {
    'nesting-rules': true
  }
})
  • browsers: 參加上面browserslist的介紹坠狡,就是設(shè)置瀏覽器的支持情況(不建議使用继找,直接在package.json 中設(shè)置)

  • insertBefore / insertAfter: 允許你在該插件運(yùn)行之前或者之后運(yùn)行某些插件,可以是一個(gè)或者多個(gè)

import postcssSimpleVars from 'postcss-simple-vars';

postcssPresetEnv({
  insertBefore: {
    'all-property': postcssSimpleVars
  }
})
  • autoprefixer: 設(shè)為 false 可以禁用該功能

  • preserve: 決定所有插件是否應(yīng)接收同一個(gè)preserve選項(xiàng)逃沿,該選項(xiàng)可以保留或刪除以其他方式填充的 CSS

  • importFrom: 從外部導(dǎo)入相關(guān)變量信息(如自定義媒體婴渡、自定義屬性幻锁、自定義選擇器和環(huán)境變量),這個(gè)導(dǎo)入的數(shù)據(jù)源可以是 css边臼、js 或者 json (還支持函數(shù)和直接對(duì)象傳值)哄尔。這個(gè)功能完全可以根據(jù)運(yùn)行時(shí)的 ENV 和某些自己設(shè)置的參數(shù),來(lái)決定最基礎(chǔ)的變量參數(shù)柠并,來(lái)進(jìn)行換膚或者針對(duì)PC岭接,H5單獨(dú)出套 ui,這樣能減少 ui 中樣式的大芯视琛(如果本身使用的就是 postcss.config.js 的方式進(jìn)行配置鸣戴,可以把切環(huán)境的功能放到這個(gè)配置文件中,然后動(dòng)態(tài)的加載不同的css)

postcssPresetEnv({
  importFrom: [
    /*
    @custom-media --small-viewport (max-width: 30em);
    @custom-selector :--heading h1, h2, h3;
    :root { --color: red; }
    */
    'path/to/file.css',

    /* module.exports = {
    customMedia: { '--small-viewport': '(max-width: 30em)' },
    customProperties: { '--color': 'red' },
    customSelectors: { ':--heading': 'h1, h2, h3' },
    environmentVariables: { '--branding-padding': '20px' }
    } */
    'and/then/this.js',

    /* {
    "custom-media": { "--small-viewport": "(max-width: 30em)" }
    "custom-properties": { "--color": "red" },
    "custom-selectors": { ":--heading": "h1, h2, h3" },
    "environment-variables": { "--branding-padding": "20px" }
    } */
    'and/then/that.json',

    {
      customMedia: { '--small-viewport': '(max-width: 30em)' },
      customProperties: { '--color': 'red' },
      customSelectors: { ':--heading': 'h1, h2, h3' },
      environmentVariables: { '--branding-padding': '20px' }
    },
    
    () => {
      const customMedia = { '--small-viewport': '(max-width: 30em)' };
      const customProperties = { '--color': 'red' };
      const customSelectors = { ':--heading': 'h1, h2, h3' };
      const environmentVariables = { '--branding-padding': '20px' };

      return { customMedia, customProperties, customSelectors, environmentVariables };
    }
  ]
});
  • exportTo: 與importFrom功能相反瘟栖,這個(gè)是導(dǎo)出相關(guān)變量(這里應(yīng)該是鼓勵(lì)我們把變量都放在一個(gè)公共的文件下葵擎,這樣便于維護(hù))

stage 2及以上的css語(yǔ)法

就是開啟默認(rèn)配置可以直接使用的css語(yǔ)法

  • all: 定義元素的所有屬性的重置的屬性 [stage 3 下面以數(shù)字簡(jiǎn)寫]
a  {
   all:initial ; 
}
  • :any-link 用于匹配錨元素的偽類,不管是否被訪問(wèn)(一般情況下a標(biāo)簽被點(diǎn)擊后a標(biāo)簽會(huì)使用:visited的設(shè)置信息半哟,這個(gè)的屬性的設(shè)置不受影響) [2]
nav:any-link> span  {
   background-color:yellow ; 
}
  • break屬性:用于定義多列布局中中斷行為的屬性 [3]

    • break-inside: 描述了在多列布局頁(yè)面下的內(nèi)容盒子如何中斷
    • break-after: 描述在生成的盒子之后的頁(yè)面酬滤,列或區(qū)域中斷行為
    • break-before: 描述列或區(qū)域在生成的盒子之前應(yīng)如何處理中斷
  • case-insensitive attributes:(看不明白,看意思是不區(qū)分大小寫) [2]

  • custom properties:用于定義CSS屬性接受的自定義值 [3]

img {
  --some-length: 32px;

  height: var(--some-length);
  width: var(--some-length);
}
  • :dir偽類 基于方向性匹配元素的偽類 [2]
  • double-position-gradients: 圓錐形漸變[2]
.pie_chart {
  background-image: conic-gradient(yellowgreen 40%, gold 0deg 75%, #f06 0deg);
}
  • :focus-visible: 焦點(diǎn)可見的偽類 [2]
  • :focus-within: 處于焦點(diǎn)狀態(tài)的偽類 [2]
  • font-variant: 設(shè)置小型大寫字母的字體顯示文本寓涨,這意味著所有的小寫字母均會(huì)被轉(zhuǎn)換為大寫盯串,但是所有使用小型大寫字體的字母與其余文本相比,其字體尺寸更小 [3]
  • gap屬性 [3]

該屬性是用來(lái)設(shè)置網(wǎng)格行與列之間的間隙(gutters)戒良,是row-gap 和 column-gap的簡(jiǎn)寫形式

  • gray(): 用于指定完全去飽和顏色的功能 [2]
  • alpha:十六進(jìn)制顏色表示法 比一般的3/6表示法体捏,多1/2個(gè)字符,可以指定透明度 [2]
  • hwb(): 用于通過(guò)色調(diào)指定顏色然后將白度和黑度指定為混合的功能 [2]
  • image-set(): 根據(jù)用戶分辨率指定引用不同的圖像源 [2]
// resolve是postcss-assets的功能糯崎,下面有介紹
.foo {
    background-image: image-set(resolve('logo1x.jpg') 1x,
                                resolve('logo2x.jpg') 2x,
                                resolve('logo-print.jpg') 600dpi);
}
...
// become
.foo {
    background-image: url(resolve('logo.jpg'));
}
@media (-webkit-min-device-pixel-ratio: 2), (min-resolution: 192dpi) {.foo {
    background-image: url(resolve('logo.jpg'));
}
}
@media (-webkit-min-device-pixel-ratio: 6.25), (min-resolution: 600dpi) {.foo {
    background-image: url(resolve('logo.jpg'));
}
}
  • lab() 使用lab表示顏色 [2]
  • lch() 使用lch表示顏色 [2]
  • logical properties and values(流相對(duì)的屬性和值) [2]
span:first-child {
  float: inline-start;
  margin-inline-start: 10px;
}
  • :matches 匹配偽類几缭,可以一次設(shè)置多個(gè)屬性值 [2]
p:matches(:first-child, .special) {
  margin-top: 1em;
}

  • :not 否定偽類,設(shè)置不在當(dāng)前范圍 [2]
p:not(:first-child, .special) {
  margin-top: 1em;
}

  • 媒體查詢范圍 使用普通比較符合定義范圍 [3]
@media (width < 480px) {}

@media (480px <= width < 768px) {}

@media (width >= 768px) {}
  • overflow 溢出屬性設(shè)置 [2]
  • overflow-wrap 定義是否在單詞中插入換行符來(lái)防止溢出屬性 [2]
  • place 定義對(duì)齊屬性 [2]
  • rebeccapurple 一個(gè)特殊的顏色值 [2]
html  {
   color:rebeccapurple ; 
}

  • system-ui 匹配通用字體 [2]
body  {
   font-family:system-ui ; 
}

stage 1 的css語(yǔ)法

因?yàn)樵O(shè)定的stage為2沃呢,如果要啟用需要在features配置中開啟年栓,對(duì)應(yīng)的id可以在插件api中查看,對(duì)應(yīng)的id就是英文加中劃線薄霜,有感覺對(duì)不上的可以去對(duì)應(yīng)github的js文件中查看

postcssPresetEnv({ 
    stage: 2,
    browsers: ['> 1%'],
    features: {
      'nesting-rules': true,
      'custom-media-queries': true,
      'custom-selectors': true
    }
})
  • 自定義媒體查詢
@custom-media --small-viewport (max-width: 30em);

@media (--small-viewport) {
  h1 {font-size: 16px}
}
...
// 轉(zhuǎn)碼為
@media (max-width: 30em) {
  h1 {font-size: 16px}
}

最大最小寬度某抓,可以使用>= <=代替

@custom-media --small-viewport (width >= 500px) and (width <= 1200px);

@media (--small-viewport) {
  h1 {font-size: 16px}
}
...
// 轉(zhuǎn)為
@media (min-width: 500px) and (max-width: 1200px) {
  h1 {font-size: 16px}
}
  • 自定義選擇器

CSS 擴(kuò)展規(guī)范(CSS Extensions)中允許創(chuàng)建自定義選擇器,可以使用@custom-selector”來(lái)定義自定義選擇器

@custom-selector :--heading h1, h2, h3, h4, h5, h6;
 
:--heading {
 font-weight: bold;
}

運(yùn)行后變?yōu)?/p>

h1,
h2,
h3,
h4,
h5,
h6 {
 font-weight: bold;
}

stage 0的css語(yǔ)法

  • 嵌套(使用的場(chǎng)景很多惰瓜,也一并開啟使用)

減少重復(fù)的選擇器聲明否副,通過(guò)兩種方式進(jìn)行嵌套:第一種方式要求嵌套的樣式聲明使用“&”作為前綴,“&”只能作為聲明的起始位置崎坊;第二種方式的樣式聲明使用“@nest”作為前綴备禀,并且“&”可以出現(xiàn)在任意位置

// 嵌套只能使用&開頭,除非前綴有@nest
.message {
 font-weight: normal;
 & .header {
   font-weight: bold;
 }
  @nest .body & {
   color: black;
 }
}

運(yùn)行后

.message {
 font-weight: normal
}
.message .header {
 font-weight: bold;
}
.body .message {
 color: black;
}

postcss-assets

引用外部資源時(shí),可以通過(guò)這個(gè)插件設(shè)置資源查找路徑痹届,簡(jiǎn)化在樣式文件中插入圖片的操作

安裝

npm i --save-dev postcss-assets

// 設(shè)置loadPaths指定查找路徑
assets({
  loadPaths: ['src/images']
}),

這時(shí)如果在main.css的文件中呻待,如果這么設(shè)置一個(gè)類

// 配置resolve,指定在查找路徑下,搜索圖片
.logo {
 background-image: resolve('logo.jpg');
}
...
// 編譯后會(huì)變成,自動(dòng)識(shí)別了
.logo {
 background-image: url('/src/images/logo.jpg');
}

這里會(huì)要求圖片是目錄下是存在的队腐,如果不存在進(jìn)行編譯時(shí)會(huì)報(bào)錯(cuò),loadPaths 是個(gè)數(shù)組奏篙,相當(dāng)于是多個(gè)搜索的目錄柴淘,只要圖片在某一個(gè)目錄下即可,不過(guò)從編譯時(shí)性能角度來(lái)考慮秘通,一定不可以設(shè)置過(guò)多的目錄为严,否則一定會(huì)影響編譯速度

postcss-assets 還有其他幾項(xiàng)設(shè)置:

  • basePath: 如果postcss.config.js不在項(xiàng)目的根目錄可以使用這個(gè)參數(shù)就行修改,比如我這里肺稀,就是把配置文件在根目錄下第股,這樣我在設(shè)置loadPaths時(shí),不用再去考慮其他路徑的問(wèn)題话原,可以從當(dāng)前位置夕吻,直接設(shè)置圖片目錄為src/images,一般這種配置文件感覺放在根目錄最好繁仁,這樣可以很方便別人查看
  • baseUrl: 沒特別弄明白這參數(shù)是什么意思涉馅,好像是在服務(wù)器運(yùn)行時(shí),設(shè)置url黄虱,不過(guò)理解不了稚矿,部署到生產(chǎn)環(huán)境的代碼,肯定時(shí)編譯后的代碼捻浦,不能在線上再實(shí)時(shí)編譯吧晤揣。。朱灿。
  • cachebuster: 是否設(shè)置緩存昧识,默認(rèn)是false
// 比如如果設(shè)為true,圖片后就會(huì)加一串hash值
.logo {
 background-image: url('/src/images/logo.jpg?1637e45dd90');
}
  • loadPaths: 設(shè)置查找特定目錄
  • relative: 和URL解析有關(guān)母剥,沒試出來(lái)做什么用的滞诺。。环疼。使用默認(rèn)的false习霹,禁用相對(duì)url解析
  • cache: 默認(rèn)為false,如果引入文件沒有發(fā)生變化炫隶,則有限使用緩存文件淋叶,感覺應(yīng)該和cachebuster配套使用,能提升編譯速度

另外這個(gè)插件伪阶,還支持通過(guò)圖片進(jìn)行相關(guān)設(shè)置

  • inline: 是把圖片轉(zhuǎn)成base64文件煞檩,估計(jì)要慎用处嫌,如果圖片很多的話,會(huì)影響編譯速度
  • width: 是獲取一張圖片的寬度斟湃,height是獲取一張圖片的高度
.logo {
 background-image: inline('logo.jpg');
 width: width('logo.jpg');
 height: height('logo.jpg');
}
...
// 運(yùn)行后
.logo {
 background-image: ...base64的圖片
 width: 493px;
 height: 448px;
}

cssnano

webpack4+ 的版本熏迹,已經(jīng)集成了cssnano,mode 設(shè)為生產(chǎn)模式就會(huì)自動(dòng)啟用這個(gè)插件

npm install --save-dev cssnano

// 如果單獨(dú)使用凝赛,可以這么配置
module.exports = {
    plugins: [
        require('cssnano')({
            preset: 'default',
        }),
    ],
};

使用 postcss 實(shí)現(xiàn)一個(gè) sass

postcss 可自主定義相關(guān)插件的使用注暗,組合出適合自己使用的功能,借助 postcss 的插件來(lái)實(shí)現(xiàn)一個(gè)類 sass

相關(guān)插件介紹

  • postcss 基礎(chǔ)功能包
  • postcss-advanced-variables 提供嵌套類似 sass 的變量墓猎、@if捆昏、@else、@for毙沾、@each骗卜、@mixin、@include左胞、@content
  • postcss-scss 使 postcss 中可以正常使用 sass 中的 #{$var-name} 變量形式
  • postcss-apply
  • postcss-assets
  • postcss-import 使在.pcss文件可以使用@import引入樣式文件
  • postcss-preset-env 一個(gè)對(duì)未來(lái)css語(yǔ)法規(guī)則寇仓,實(shí)現(xiàn)比較好的插件
  • postcss-cli 提供了終端運(yùn)行的能力

@import

使用 postcss-import 插件

const atImport = require("postcss-import");
module.exports = {
  plugins: [
    atImport(),

元素嵌套

使用 postcss-preset-env 插件 stage:0 中的 nesting-rules

require('postcss-preset-env')({
    stage: 2,
  browsers: ['> 1%'],
  features: {
    'nesting-rules': true
  }
})

具體寫法上和sass嵌套的寫法有些不一樣,不過(guò)這種寫法是未來(lái)css的標(biāo)準(zhǔn)罩句,以這個(gè)為主要寫法

nav {
  & ul {
    margin: 0;
    padding: 0;
    list-style: none;
  }

  & li {
    display: inline-block;
  }

  & a {
    display: block;
    padding: 6px 12px;
    text-decoration: none;
    & span {
      color: $red;
    }
  }
}

變量焚刺、@if、@else门烂、@for乳愉、@each、@mixin屯远、@include蔓姚、@content

使用 postcss-advanced-variables 這個(gè)插件,這個(gè)插件能實(shí)現(xiàn)sass變量的大部分功能慨丐,不過(guò)一個(gè)特殊的語(yǔ)法#{$var-name}需要使用到 postcss-scss 這個(gè)插件坡脐,并且在postcss.config.js 中設(shè)置 parserpostcss-scss

const advanced = require("postcss-advanced-variables");
module.exports = {
  parser: "postcss-scss",
  plugins: [
    advanced(),
    ...
// 變量
$font-size: 1.25em;
$font-stack: "Helvetica Neue", sans-serif;
$primary-color: #333;

body {
  font: $font-size $(font-stack);
  color: #{$primary-color};
}
...
// 轉(zhuǎn)為
body {
  font: 1.25em "Helvetica Neue", sans-serif;
  color: #333;
}
// @if、@else
$type: monster;
 
p {
  @if $type == ocean {
    color: blue;
  } @else {
    color: black;
  }
}
...
// 轉(zhuǎn)為
p {
    color: black
}
// @for
@for $i from 1 through 5 by 2 {
  .width-#{$i} {
    width: #{$i}0em;
  }
}
...
// 轉(zhuǎn)為
.width-1 {
    width: 10em;
  }
.width-3 {
    width: 30em;
  }
.width-5 {
    width: 50em;
  }
// @each
@each $animal in (red, yellow, black, white) {
  .#{$animal}-icon {
    color: #{$animal};
  }
}
...
// 轉(zhuǎn)為
.red-icon {
    color: red;
  }
.yellow-icon {
    color: yellow;
  }
.black-icon {
    color: black;
  }
.white-icon {
    color: white;
  }
// @mixin @include
@mixin heading-text {
  color: #242424;
  font-size: 4em;
}
 
h1, h2, h3 {
  @include heading-text;
}
...
// 轉(zhuǎn)為
h1,
h2,
h3 {
  color: #242424;
  font-size: 4em;
}

屬性嵌套

postcss-nested-props

const nestedProps = require("postcss-nested-props");
module.exports = {
  plugins: [
    nestedProps(),
.funky {
  font: {
    family: fantasy;
    size: 30em;
    weight: bold;
  }
}
...
// 轉(zhuǎn)為
.funky {
    font-family: fantasy;
    font-size: 30em;
    font-weight: bold
}

Extend/Inheritance(擴(kuò)展/繼承)

postcss-extend

const extend = require("postcss-extend");
module.exports = {
  plugins: [
    extend(),
// 這里和sass有點(diǎn)不同房揭,使用 @define-placeholder 而非 % 導(dǎo)出樣式塊
@define-placeholder message-shared {
  border: 1px solid #ccc;
  padding: 10px;
  color: #333;
}
.message {
  @extend message-shared;
}

.error {
  border: 1px #f00;
  background-color: #fdd;
}
.seriousError {
  @extend .error;
  border-width: 3px;
}
...
// 轉(zhuǎn)為
.message {
  border: 1px solid #ccc;
  padding: 10px;
  color: #333;
}
.error, .seriousError {
  border: 1px #f00;
  background-color: #fdd;
}
.seriousError {
  border-width: 3px;
}

添加calc()計(jì)算

postcss-calc

const calc = require("postcss-calc");
module.exports = {
  plugins: [
    calc(),
@mixin columns_calc($count) {
  width: calc(100% / $count);
  @if $count > 1 {
    float: left;
  }
}
.column_calculated {
  @include columns_calc(2);
}
...
// 轉(zhuǎn)為
.column_calculated {
  width: 50%;
  float: left;
}

添加了這些插件备闲,基本就可以完全可以滿足正常開發(fā)需求

完整配置如下:

const postcssPresetEnv = require("postcss-preset-env");
const atImport = require("postcss-import");
const advanced = require("postcss-advanced-variables");
const nestedProps = require("postcss-nested-props");
const extend = require("postcss-extend");
const calc = require("postcss-calc");
module.exports = {
  parser: "postcss-scss",
  plugins: [
    atImport(),
    advanced(),
    nestedProps(),
    extend(),
    calc(),
    postcssPresetEnv({
      stage: 2,
      browsers: "> 3%",
      features: {
        "nesting-rules": true
      }
    })
  ]
};

獨(dú)立使用postcss

可以通過(guò) postcss-cli 這個(gè)插件構(gòu)建一個(gè)獨(dú)立使用的 css 處理平臺(tái),可在 package.json 中添加如下命令

  "scripts": {
    "build:pc": "npx postcss src/main.pc.css -o dist/main.pc.css",
    "build:h5": "npx postcss src/main.h5.css -o dist/main.h5.css"
// src/main.pc.css
@import 'normalize.css';
@import 'reset.css';
@import 'variables.css';
@import 'common.css';
@import 'common.mixin.css';
@import 'layout.mixin.css';
@import 'layout.css';
@import 'layout-flex.css';
@import 'button.mixin.css';
@import 'button.css';
@import 'button-group.css';
@import 'skeleton.mixin.css';
@import 'skeleton.css';
@import 'breadcrumb.css';
@import 'dropdown.css';
@import 'menu.css';
@import 'pagination.mixin.css';
@import 'pagination.css';
@import 'step.css';
@import 'checkbox.css';
@import 'cascader.css';
@import 'form.css';
@import 'calendar.css';
@import 'input-number.css';
@import 'rate.css'

這里由一個(gè)統(tǒng)一入口文件捅暴,控制針對(duì)PC恬砂,H5不同的樣式表的輸出,在入口文件中蓬痒,可以設(shè)置引入不同的變量(比如上面例子中的 variables.css 正常開發(fā)中泻骤,可以細(xì)化成variables.pc.css或者variables.orange.css 這類的樣式),讓換膚類的功能也比較容易實(shí)現(xiàn)

避免編譯器對(duì)pcss文件報(bào)錯(cuò)

我使用的是我使用的是vscode,引用插件后寫的樣式狱掂,編譯器基本是不認(rèn)識(shí)的演痒,會(huì)給你報(bào)錯(cuò),所以這里說(shuō)下如何避免對(duì)pcss的報(bào)錯(cuò)趋惨,其他編譯器應(yīng)該也有類似的方法

對(duì)vscode添加對(duì).pcss文件的支持

  • 安裝postcss-sugar-language插件
  • 進(jìn)入setting鸟顺,搜索files.associations在其中添加如下內(nèi)容
"*.css": "postcss"

設(shè)置 "postcss.validate": false,避免檢查器對(duì) pcss 進(jìn)行檢查

css module

(參考CSS in JS 簡(jiǎn)介
css modulecss in js 都是社區(qū)針對(duì) css 作用域提出的解決方案器虾,從實(shí)際開發(fā)過(guò)程中诊沪,感覺 css module 的方式,更適合分工合作的要求曾撤。

現(xiàn)在開發(fā)中,不管你使用什么框架晕粪,基本的流程大概都是:先做靜態(tài)頁(yè)面挤悉,再接動(dòng)態(tài)數(shù)據(jù)。這里很容易就會(huì)形成兩條工作線:一類專門進(jìn)行重構(gòu)巫湘,與設(shè)計(jì)師装悲、交互對(duì)接完成視覺實(shí)現(xiàn);另一類專門與產(chǎn)品經(jīng)理尚氛、后端對(duì)接業(yè)務(wù)需求(體量大的公司會(huì)拆分成兩個(gè)工種诀诊,小公司自然是全干了,但是工作場(chǎng)景多半如此)阅嘶。

css in js 的方式属瓣,更符合獨(dú)立組件的封裝型。從樣式讯柔、邏輯到內(nèi)容展現(xiàn)抡蛙,在一個(gè) js 中都實(shí)現(xiàn),不需要再引入其他文件魂迄,如果是寫 ui 組件這種方式是極好的粗截。

但是如果是正常的開發(fā)需求,你用這種方式捣炬,就表示樣式問(wèn)題的改動(dòng)熊昌、修復(fù),業(yè)務(wù)邏輯的實(shí)現(xiàn)湿酸,都是在一個(gè)文件中進(jìn)行婿屹,不利于分工合作。

個(gè)人感覺 css in js 方式會(huì)讓 js 文件變得混亂稿械,可讀性下降(正常開發(fā)就算是狀態(tài)管理选泻,一般都會(huì)被拆分成一個(gè)個(gè)獨(dú)立的文件)。而且沒辦法單獨(dú)輸出樣式文件,沒辦法把樣式文件丟在某個(gè) cdn 服務(wù)器下页眯,也影響組件的復(fù)用性梯捕。如果要復(fù)用某個(gè)組件(業(yè)務(wù)組件)就表示要接受這個(gè)組件自帶的樣式,稍微調(diào)整點(diǎn)字號(hào)顏色啥的窝撵,就要單獨(dú)加個(gè)接收參數(shù)傀顾,或者新建個(gè)類似 list-red 的新組件(如果是引入樣式的方式,完全可以通過(guò)再引入這個(gè)組件的外層加個(gè)類似 <div class='red-list'><list /></div>碌奉,在外層樣式文件中直接控制短曾,也很容易擴(kuò)展多個(gè)不同樣式、換膚啥的)赐劣。

css in js 方式對(duì)重構(gòu)人員也不友好嫉拐,他們之前查看樣式問(wèn)題,直接修改樣式文件部署后就能看出問(wèn)題能不能解決魁兼,現(xiàn)在需要修改 js 文件等js文件部署后才能查看改動(dòng)是否生效(如果再碰到分支不同婉徘,版本不同的情況,那更熱鬧了咐汞。盖呼。。)

啟用

參考了 CSS Modules 用法教程

配合 css-loader 使用化撕,在 webpack 配置項(xiàng)中如下設(shè)置:

{test: /\.pcss/, use: [MiniCssExtractPlugin.loader, 'css-loader?modules', 'postcss-loader']}几晤,

這樣就開啟了 css module,它的使用會(huì)把對(duì)應(yīng)的樣式名變成一種有規(guī)律植阴,但不可預(yù)期的名稱蟹瘾,比如

/// main.pcss
/// 由于樣式文件本身并沒有要求 .classname 不能重復(fù),所以要自己保證不要重復(fù)墙贱,否則針對(duì)同一類名會(huì)轉(zhuǎn)出多個(gè)變量名热芹,在使用時(shí)會(huì)有問(wèn)題
.box {
    border-radius:5px;
}
.info {
    color: red;
    font-size: 24px;
}
...
/// app.vue
<template>
    <div :class="$style.info">{{ msg }}</div>
</template>
import style from '../style/main.pcss';
...
computed: {
  $style () {
    return style;
  }
}

$style 的使用方式參考了 vue-loader 的 CSS Modules 方案,vue loader 會(huì)使用 $style 的計(jì)算屬性惨撇,向組件注入 CSS Modules 局部對(duì)象

style 會(huì)輸出為(value 值是一個(gè)動(dòng)態(tài)值)

{box: "_2sI8WybUY_1NGPVWmXjdbV", info: "_hA0iOLbXZy9PpOuCjpkc"}

組件內(nèi)直接使用其中的定義的樣式名伊脓,會(huì)自動(dòng)替換成這些名稱,樣式文件也會(huì)自動(dòng)轉(zhuǎn)成這些名稱魁衙,這樣可以解決 css 的樣式?jīng)_突(污染)的問(wèn)題报腔,全局污染的問(wèn)題,也可以算是解決依賴的問(wèn)題剖淀,組件只需要引入自己相關(guān)的樣式纯蛾,在這個(gè)相關(guān)樣式文件中定義自己需要使用的樣式,再通過(guò) $style 的形式給相關(guān)組件使用纵隔。

vue 的寫法稍微麻煩點(diǎn)(如果用 JSX 會(huì)簡(jiǎn)單些)翻诉,如果是在 react 中可以直接使用

import style from '../style/main.css';

class App extends Component {
    render () {
        return <div className={style.info}>app info</div>
    }
}

全局作用域

在引入的樣式文件中炮姨,默認(rèn)會(huì)對(duì)所有樣式進(jìn)行轉(zhuǎn)換,如果你的樣式只是想通過(guò)普通方式使用碰煌,可以有兩種方案:

  • 只針對(duì) .pcss 開啟 css module舒岸,.css 不開啟
/// webpack.config.js
{test: /\.css/, use: [MiniCssExtractPlugin.loader, 'css-loader']},
{test: /\.pcss/, use: [MiniCssExtractPlugin.loader, 'css-loader?modules', 'postcss-loader']}
...
/// global.css
body {
    font-size: 18px;
    background: #cccccc;
}
...
/// app.vue
import '../style/global.css';
import style from '../style/main.pcss'; // 這里雖然是分開導(dǎo)入,但是最終會(huì)合并和一個(gè)樣式文件
...
/// main.css 導(dǎo)出的樣式文件
body {
    font-size: 18px;
    background: #cccccc;
}
._2sI8WybUY_1NGPVWmXjdbV {
    border-radius:5px;
}
._hA0iOLbXZy9PpOuCjpkc {
    color: red;
    font-size: 24px;
}
  • 在待編譯的樣式文件使用 :global(.className) (也可以省略為 :global .className)的寫法芦圾,這樣這個(gè)對(duì)應(yīng)的樣式也不會(huì)編譯

:local 可以設(shè)置哪些需要轉(zhuǎn)蛾派,因?yàn)槟J(rèn)就是轉(zhuǎn)換,沒必要再加一層說(shuō)明其需要轉(zhuǎn)換

對(duì)于需要轉(zhuǎn)換的个少,請(qǐng)一直使用 .classname洪乍,不要使用 id

/// main.pcss
...
:global(body)  {
    font-size: 18px;
    background: #cccccc;
}

Composing(組合) 及 Importing(導(dǎo)入)

組合的意義并不是把樣式代碼進(jìn)行混合,而是在于使用了組合的類名夜焦,在引用時(shí)會(huì)包含其組合的子類

.box {
    border-radius:5px;
}
.info {
    color: red;
    font-size: 24px;
}
.foo {
    composes: box;
    composes: info;
    padding: 10px;
}
/// 經(jīng)過(guò)轉(zhuǎn)換后對(duì)應(yīng)的json信息如下
box: "src-style-main__box--2sI8W",
info: "src-style-main__info--_hA0i",
foo: "src-style-main__foo--LiN2X src-style-main__box--2sI8W src-style-main__info--_hA0i",
/// 如果我們使用 $style.foo 還會(huì)包含其他兩個(gè)子類的內(nèi)容

composes 還可以從其他樣式模塊中導(dǎo)入樣式進(jìn)行組合

.foo {
    composes: main-title header-title from './color.css';
    padding: 10px;
}

@value

css 變量的解決方案很多壳澳,這個(gè)是 css-loader 的方案

官方有個(gè)命名建議:v- 定義value值, s- 選擇器 m- 定義 media 規(guī)則

@value v-primary: #BF4040;
@value s-black: black-selector;
@value m-large: (min-width: 960px);

.header {
  color: v-primary;
  padding: 0 10px;
}
:global .s-black {
  color: black;
}
@media m-large {
  .header {
    padding: 0 20px;
  }
}

定制編譯后的類名

css-loader 默認(rèn)的哈希算法是 [hash:base64],轉(zhuǎn)出的就是這種 _2sI8WybUY_1NGPVWmXjdbV茫经,這個(gè)轉(zhuǎn)換后的名稱是可以定制的

// 參數(shù)比較長(zhǎng)钾埂,再使用拼接的寫法,看起來(lái)不美觀
loader: 'css-loader',
options: {
  modules: {
    localIdentName: '[path][name]__[local]--[hash:base64:5]'
  } // 注意是在 modules 下設(shè)置 localIdentName
}

按官方建議

  • 開發(fā)環(huán)境使用 [path][name]__[local]--[hash:base64:5]
  • 生產(chǎn)環(huán)境使用 [hash:base64]

這樣轉(zhuǎn)出的類名就類似 src-style-main__box--2sI8W科平,能看出路徑和使用模塊,方便定位樣式問(wèn)題所在的

css loader 參數(shù)

名稱 類型 默認(rèn) 描述
url {Boolean|Function} true 啟用/禁止 url() 功能
import {Boolean|Function} true 啟用/禁用 @import 處理
modules {Boolean|String|Object} false 啟用/禁用 CSS Modules 以及相關(guān)配置
sourceMap {Boolean} false 啟用/禁用 map 功能
importLoaders {Number} 0 在 css-loader 之前使用多少個(gè)加載器(默認(rèn)姜性,別去動(dòng)這個(gè)值瞪慧,按 webpack 中的設(shè)置的 use 順序去執(zhí)行使用 loader)
localsConvention {String} 'asIs' 導(dǎo)出的 JSON 對(duì)應(yīng)的 Key 的規(guī)則
onlyLocals {Boolean} false 影響打包時(shí)的 loader 順序,一些 SSR 場(chǎng)景下可以需要設(shè)置這個(gè)值部念,一般情況下別用
esModule {Boolean} false 是否啟用 es module

url

/// 先安裝 url-loader 處理圖片弃酌,并添加相關(guān)配置信息
{
  test: /\.(png|svg|jpg|jpeg|gif)$/,
  use: "url-loader"
},
...
/// main.pcss
.foo {
  color: red;
  font-size: 14px;
  background: url("../image/timg.jpeg"); // 此處設(shè)定了背景圖
}

按如上設(shè)置,轉(zhuǎn)換出的 css 會(huì)對(duì)圖片進(jìn)行處理儡炼,但如果設(shè)置這個(gè)值為 false

{
  loader: "css-loader",
  options: {
    modules: true,
    url: false // 這個(gè)值默認(rèn)是 true
  }
},

轉(zhuǎn)換出的 css 就不會(huì)對(duì) url() 進(jìn)行處理妓湘,原樣輸出

/// 不如處理 background: url("../image/timg.jpeg");
/// 這個(gè) url 還可以設(shè)置為函數(shù),在這里可以控制乌询,只有指定圖片名會(huì)轉(zhuǎn)榜贴,進(jìn)行差異化處理
url: (url, resourcePath) => {
    // url ../image/timg.jpeg
  // resourcePath - css 的絕對(duì)路徑

  // 不處理 `img.png` urls
  if (url.includes('img.png')) {
    return false;
  }

  return true;
},

import

這個(gè)值和 url 功能類似,只不過(guò)這里是控制文件的導(dǎo)入導(dǎo)出妹田,這個(gè)值也一樣可以設(shè)置 true 或 false唬党,如果這樣直接設(shè)置,那這肯定有問(wèn)題鬼佣,這個(gè)參數(shù)要么不設(shè)置驶拱,要設(shè)置一定是要對(duì)url進(jìn)行過(guò)濾

/// @import "./color.css";
import: (parsedImport, resourcePath) => {
    // parsedImport { url: './color.css', media: '' }
  // parsedImport.url - `@import` 文件時(shí)對(duì)應(yīng)的路徑 
  // parsedImport.media -  `@import` 媒體查詢時(shí)對(duì)應(yīng)的路徑
  // resourcePath - css 文件的絕對(duì)路徑

  // 包含 `style.css` 不進(jìn)行合并處理
  if (parsedImport.url.includes('style.css')) {
    return false;
  }

  return true;
},

@import 是一個(gè)廣泛被支持的 css 屬性,大于 IE9 的瀏覽器就可以正常使用

modules

true 或 false 啟用/禁止(還可以通過(guò)設(shè)置 modules 的值為 'local''global'啟用/禁止) css modules

前面提到的 :global :local晶衷、Composing Importing 蓝纲、@value阴孟、localIdentName 都是 modules 的配置信息,modules 可以接收一個(gè)對(duì)象進(jìn)行其他配置

modules: {
  mode: 'local', // 設(shè)置 local 啟用 global 禁用 css 模塊
  exportGlobals: true,
  localIdentName: '[path][name]__[local]--[hash:base64:5]', // 編譯后的類名
  context: path.resolve(__dirname, 'src'),
  hashPrefix: 'my-custom-hash',
},
  • mode 除了 local global 外税迷,還有一個(gè)值是 pure永丝,使用這個(gè)值就要求樣式文件中必須是純的選擇器,不能使用 global local 進(jìn)行包裹
/// 在 mode 為 pure 時(shí)翁狐,會(huì)提示編譯出錯(cuò)
 :local(.zoo)
...
/// mode 還可以接受一個(gè)函數(shù)形式类溢,對(duì)指定路徑的樣式文件進(jìn)行特殊處理(什么文件開啟轉(zhuǎn)換,什么文件不開啟)露懒,返回值只能是這三個(gè)值
mode: (resourcePath) => {
  if (/pure.css$/i.test(resourcePath)) {
    return 'pure';
  }

  if (/global.css$/i.test(resourcePath)) {
    return 'global';
  }

  return 'local';
}, 
  • exportGlobals 按描述應(yīng)該是控制輸出類名的名稱闯冷,不過(guò)沒沒查出有什么特別的用處,設(shè)不設(shè)都不影響使用

  • context 生成hash值相同懈词,參考那個(gè) GitHub bug 說(shuō)明蛇耀,是在某些情況下,生成的hash值出現(xiàn)重復(fù)的情況坎弯,然后借助這個(gè)參數(shù)纺涤,解決此問(wèn)題,不過(guò)我試了很多情況抠忘,沒試出來(lái)生成 hash 相同的情況

  • hashPrefix 設(shè)定組自己的 hash 值規(guī)則撩炊,一般無(wú)須設(shè)置

  • getLocalIdent 設(shè)置編譯后的規(guī)則名,同 localIdentName 只不過(guò)這是個(gè)函數(shù)崎脉,能設(shè)置的更細(xì)拧咳,一般用 localIdentName

  • localIdentRegExp 沒試出干什么用

localsConvention

這個(gè)設(shè)定導(dǎo)出 JSON 時(shí),key值和類名如何映射囚灼,默認(rèn)值是 'asIs'

loader: 'css-loader',
options: {
  modules: {
    mode: 'local',
    localIdentName: '[path][name]__[local]--[hash:base64:5]'
  },
    localsConvention: 'asIs'
}
...
.infoNews {
    font-size: 35px;
}
.info-old {
    color: white;
}
.info_dashes {
    color: salmon;
}
.info {
    color: red;
}
...
/// 默認(rèn) asIs骆膝,類名是啥,導(dǎo)出的就是啥
info: "src-components-page1-index__info--10GK2"
info-old: "src-components-page1-index__info-old--k163w"
infoNews: "src-components-page1-index__infoNews--1uma1"
info_dashes: "src-components-page1-index__info_dashes--FVVUn"
...
/// camelCase 駝峰灶体,會(huì)把非駝峰的命名轉(zhuǎn)為駝峰阅签,并保留之前的類名
info: "src-components-page1-index__info--10GK2"
info-old: "src-components-page1-index__info-old--k163w"
infoDashes: "src-components-page1-index__info_dashes--FVVUn" // 值同 info_dashes
infoNews: "src-components-page1-index__infoNews--1uma1"
infoOld: "src-components-page1-index__info-old--k163w" // 值同 info-old
info_dashes: "src-components-page1-index__info_dashes--FVVUn"
...
/// camelCaseOnly 與駝峰類似,只不過(guò)不會(huì)保留非駝峰的轉(zhuǎn)換
info: "src-components-page1-index__info--10GK2"
infoDashes: "src-components-page1-index__info_dashes--FVVUn"
infoNews: "src-components-page1-index__infoNews--1uma1"
infoOld: "src-components-page1-index__info-old--k163w"
...
/// dashes 一樣也是轉(zhuǎn)駝峰蝎抽,只不過(guò)這里限制只轉(zhuǎn) ``-`` 號(hào)
info: "src-components-page1-index__info--10GK2"
info-old: "src-components-page1-index__info-old--k163w"
infoNews: "src-components-page1-index__infoNews--1uma1"
infoOld: "src-components-page1-index__info-old--k163w"
info_dashes: "src-components-page1-index__info_dashes--FVVUn" // 不轉(zhuǎn)換
...
/// dashesOnly 不保留轉(zhuǎn)換前的
info: "src-components-page1-index__info--10GK2"
infoNews: "src-components-page1-index__infoNews--1uma1"
infoOld: "src-components-page1-index__info-old--k163w"
info_dashes: "src-components-page1-index__info_dashes--FVVUn"

之所以會(huì)有這么個(gè)參數(shù)政钟,是因?yàn)槲覀冊(cè)谑褂? css modules 時(shí),最終可能會(huì)動(dòng)態(tài)綁定到某個(gè)組件上樟结,這是為了方便在 js 中使用

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末锥涕,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子狭吼,更是在濱河造成了極大的恐慌层坠,老刑警劉巖,帶你破解...
    沈念sama閱讀 216,372評(píng)論 6 498
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件刁笙,死亡現(xiàn)場(chǎng)離奇詭異破花,居然都是意外死亡谦趣,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,368評(píng)論 3 392
  • 文/潘曉璐 我一進(jìn)店門座每,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)前鹅,“玉大人,你說(shuō)我怎么就攤上這事峭梳〗⒒妫” “怎么了?”我有些...
    開封第一講書人閱讀 162,415評(píng)論 0 353
  • 文/不壞的土叔 我叫張陵葱椭,是天一觀的道長(zhǎng)捂寿。 經(jīng)常有香客問(wèn)我,道長(zhǎng)孵运,這世上最難降的妖魔是什么秦陋? 我笑而不...
    開封第一講書人閱讀 58,157評(píng)論 1 292
  • 正文 為了忘掉前任,我火速辦了婚禮治笨,結(jié)果婚禮上驳概,老公的妹妹穿的比我還像新娘。我一直安慰自己旷赖,他們只是感情好顺又,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,171評(píng)論 6 388
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著等孵,像睡著了一般待榔。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上流济,一...
    開封第一講書人閱讀 51,125評(píng)論 1 297
  • 那天,我揣著相機(jī)與錄音腌闯,去河邊找鬼绳瘟。 笑死,一個(gè)胖子當(dāng)著我的面吹牛姿骏,可吹牛的內(nèi)容都是我干的糖声。 我是一名探鬼主播,決...
    沈念sama閱讀 40,028評(píng)論 3 417
  • 文/蒼蘭香墨 我猛地睜開眼分瘦,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼蘸泻!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起嘲玫,我...
    開封第一講書人閱讀 38,887評(píng)論 0 274
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤悦施,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后去团,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體抡诞,經(jīng)...
    沈念sama閱讀 45,310評(píng)論 1 310
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡穷蛹,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,533評(píng)論 2 332
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了昼汗。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片肴熏。...
    茶點(diǎn)故事閱讀 39,690評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖顷窒,靈堂內(nèi)的尸體忽然破棺而出蛙吏,到底是詐尸還是另有隱情,我是刑警寧澤鞋吉,帶...
    沈念sama閱讀 35,411評(píng)論 5 343
  • 正文 年R本政府宣布鸦做,位于F島的核電站,受9級(jí)特大地震影響坯辩,放射性物質(zhì)發(fā)生泄漏馁龟。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,004評(píng)論 3 325
  • 文/蒙蒙 一漆魔、第九天 我趴在偏房一處隱蔽的房頂上張望坷檩。 院中可真熱鬧,春花似錦改抡、人聲如沸矢炼。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,659評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)句灌。三九已至,卻和暖如春欠拾,著一層夾襖步出監(jiān)牢的瞬間胰锌,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 32,812評(píng)論 1 268
  • 我被黑心中介騙來(lái)泰國(guó)打工藐窄, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留资昧,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 47,693評(píng)論 2 368
  • 正文 我出身青樓荆忍,卻偏偏與公主長(zhǎng)得像格带,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子刹枉,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,577評(píng)論 2 353