国产xxxx99真实实拍_久久不雅视频_高清韩国a级特黄毛片_嗯老师别我我受不了了小说

資訊專(zhuān)欄INFORMATION COLUMN

CSS Modules詳解及React中實(shí)踐

wemall / 3035人閱讀

摘要:上例中打印的結(jié)果是對(duì)中的名都做了處理,使用對(duì)象來(lái)保存原和混淆后的對(duì)應(yīng)關(guān)系。結(jié)合實(shí)踐在處直接使用中名即可。如因?yàn)橹粫?huì)轉(zhuǎn)變類(lèi)選擇器,所以這里的屬性選擇器不需要添加。

CSS 是前端領(lǐng)域中進(jìn)化最慢的一塊。由于 ES2015/2016 的快速普及和 Babel/Webpack 等工具的迅猛發(fā)展,CSS 被遠(yuǎn)遠(yuǎn)甩在了后面,逐漸成為大型項(xiàng)目工程化的痛點(diǎn)。也變成了前端走向徹底模塊化前必須解決的難題。

CSS 模塊化的解決方案有很多,但主要有兩類(lèi)。一類(lèi)是徹底拋棄 CSS,使用 JS 或 JSON 來(lái)寫(xiě)樣式。Radium,jsxstyle,react-style 屬于這一類(lèi)。優(yōu)點(diǎn)是能給 CSS 提供 JS 同樣強(qiáng)大的模塊化能力;缺點(diǎn)是不能利用成熟的 CSS 預(yù)處理器(或后處理器) Sass/Less/PostCSS,:hover:active 偽類(lèi)處理起來(lái)復(fù)雜。另一類(lèi)是依舊使用 CSS,但使用 JS 來(lái)管理樣式依賴(lài),代表是 CSS Modules。CSS Modules 能最大化地結(jié)合現(xiàn)有 CSS 生態(tài)和 JS 模塊化能力,API 簡(jiǎn)潔到幾乎零學(xué)習(xí)成本。發(fā)布時(shí)依舊編譯出多帶帶的 JS 和 CSS。它并不依賴(lài)于 React,只要你使用 Webpack,可以在 Vue/Angular/jQuery 中使用。是我認(rèn)為目前最好的 CSS 模塊化解決方案。近期在項(xiàng)目中大量使用,下面具體分享下實(shí)踐中的細(xì)節(jié)和想法。

CSS 模塊化遇到了哪些問(wèn)題?

CSS 模塊化重要的是要解決好兩個(gè)問(wèn)題:CSS 樣式的導(dǎo)入和導(dǎo)出。靈活按需導(dǎo)入以便復(fù)用代碼;導(dǎo)出時(shí)要能夠隱藏內(nèi)部作用域,以免造成全局污染。Sass/Less/PostCSS 等前仆后繼試圖解決 CSS 編程能力弱的問(wèn)題,結(jié)果它們做的也確實(shí)優(yōu)秀,但這并沒(méi)有解決模塊化最重要的問(wèn)題。Facebook 工程師 Vjeux 首先拋出了 React 開(kāi)發(fā)中遇到的一系列 CSS 相關(guān)問(wèn)題。加上我個(gè)人的看法,總結(jié)如下:

全局污染
CSS 使用全局選擇器機(jī)制來(lái)設(shè)置樣式,優(yōu)點(diǎn)是方便重寫(xiě)樣式。缺點(diǎn)是所有的樣式都是全局生效,樣式可能被錯(cuò)誤覆蓋,因此產(chǎn)生了非常丑陋的 !important,甚至 inline !important 和復(fù)雜的選擇器權(quán)重計(jì)數(shù)表,提高犯錯(cuò)概率和使用成本。Web Components 標(biāo)準(zhǔn)中的 Shadow DOM 能徹底解決這個(gè)問(wèn)題,但它的做法有點(diǎn)極端,樣式徹底局部化,造成外部無(wú)法重寫(xiě)樣式,損失了靈活性。

命名混亂
由于全局污染的問(wèn)題,多人協(xié)同開(kāi)發(fā)時(shí)為了避免樣式?jīng)_突,選擇器越來(lái)越復(fù)雜,容易形成不同的命名風(fēng)格,很難統(tǒng)一。樣式變多后,命名將更加混亂。

依賴(lài)管理不徹底
組件應(yīng)該相互獨(dú)立,引入一個(gè)組件時(shí),應(yīng)該只引入它所需要的 CSS 樣式。但現(xiàn)在的做法是除了要引入 JS,還要再引入它的 CSS,而且 Saas/Less 很難實(shí)現(xiàn)對(duì)每個(gè)組件都編譯出多帶帶的 CSS,引入所有模塊的 CSS 又造成浪費(fèi)。JS 的模塊化已經(jīng)非常成熟,如果能讓 JS 來(lái)管理 CSS 依賴(lài)是很好的解決辦法。Webpack 的 css-loader 提供了這種能力。

無(wú)法共享變量
復(fù)雜組件要使用 JS 和 CSS 來(lái)共同處理樣式,就會(huì)造成有些變量在 JS 和 CSS 中冗余,Sass/PostCSS/CSS 等都不提供跨 JS 和 CSS 共享變量這種能力。

代碼壓縮不徹底
由于移動(dòng)端網(wǎng)絡(luò)的不確定性,現(xiàn)在對(duì) CSS 壓縮已經(jīng)到了{(lán){BANNED}}的程度。很多壓縮工具為了節(jié)省一個(gè)字節(jié)會(huì)把 "16px" 轉(zhuǎn)成 "1pc"。但對(duì)非常長(zhǎng)的 class 名卻無(wú)能為力,力沒(méi)有用到刀刃上。

上面的問(wèn)題如果只憑 CSS 自身是無(wú)法解決的,如果是通過(guò) JS 來(lái)管理 CSS 就很好解決,因此 Vjuex 給出的解決方案是完全的 CSS in JS,但這相當(dāng)于完全拋棄 CSS,在 JS 中以 Object 語(yǔ)法來(lái)寫(xiě) CSS,估計(jì)剛看到的小伙伴都受驚了。直到出現(xiàn)了 CSS Modules。

CSS Modules 模塊化方案

CSS Modules 內(nèi)部通過(guò) ICSS 來(lái)解決樣式導(dǎo)入和導(dǎo)出這兩個(gè)問(wèn)題。分別對(duì)應(yīng) :import:export 兩個(gè)新增的偽類(lèi)。

:import("path/to/dep.css") {
  localAlias: keyFromDep;
  /* ... */
}
:export {
  exportedKey: exportedValue;
  /* ... */
}

但直接使用這兩個(gè)關(guān)鍵字編程太麻煩,實(shí)際項(xiàng)目中很少會(huì)直接使用它們,我們需要的是用 JS 來(lái)管理 CSS 的能力。結(jié)合 Webpack 的 css-loader 后,就可以在 CSS 中定義樣式,在 JS 中導(dǎo)入。

啟用 CSS Modules
// webpack.config.js
css?modules&localIdentName=[name]__[local]-[hash:base64:5]

加上 modules 即為啟用,localIdentName 是設(shè)置生成樣式的命名規(guī)則。

/* components/Button.css */
.normal { /* normal 相關(guān)的所有樣式 */ }
.disabled { /* disabled 相關(guān)的所有樣式 */ }
/* components/Button.js */
import styles from "./Button.css";

console.log(styles);

buttonElem.outerHTML = ``

生成的 HTML 是

注意到 button--normal-abc5436 是 CSS Modules 按照 localIdentName 自動(dòng)生成的 class 名。其中的 abc5436 是按照給定算法生成的序列碼。經(jīng)過(guò)這樣混淆處理后,class 名基本就是唯一的,大大降低了項(xiàng)目中樣式覆蓋的幾率。同時(shí)在生產(chǎn)環(huán)境下修改規(guī)則,生成更短的 class 名,可以提高 CSS 的壓縮率。

上例中 console 打印的結(jié)果是:

Object {
  normal: "button--normal-abc546",
  disabled: "button--disabled-def884",
}

CSS Modules 對(duì) CSS 中的 class 名都做了處理,使用對(duì)象來(lái)保存原 class 和混淆后 class 的對(duì)應(yīng)關(guān)系。

通過(guò)這些簡(jiǎn)單的處理,CSS Modules 實(shí)現(xiàn)了以下幾點(diǎn):

所有樣式都是 local 的,解決了命名沖突和全局污染問(wèn)題

class 名生成規(guī)則配置靈活,可以此來(lái)壓縮 class 名

只需引用組件的 JS 就能搞定組件所有的 JS 和 CSS

依然是 CSS,幾乎 0 學(xué)習(xí)成本

樣式默認(rèn)局部

使用了 CSS Modules 后,就相當(dāng)于給每個(gè) class 名外加加了一個(gè) :local,以此來(lái)實(shí)現(xiàn)樣式的局部化,如果你想切換到全局模式,使用對(duì)應(yīng)的 :global

.normal {
  color: green;
}

/* 以上與下面等價(jià) */
:local(.normal) {
  color: green; 
}

/* 定義全局樣式 */
:global(.btn) {
  color: red;
}

/* 定義多個(gè)全局樣式 */
:global {
  .link {
    color: green;
  }
  .box {
    color: yellow;
  }
}
Compose 來(lái)組合樣式

對(duì)于樣式復(fù)用,CSS Modules 只提供了唯一的方式來(lái)處理:composes 組合

/* components/Button.css */
.base { /* 所有通用的樣式 */ }

.normal {
  composes: base;
  /* normal 其它樣式 */
}

.disabled {
  composes: base;
  /* disabled 其它樣式 */
}
import styles from "./Button.css";

buttonElem.outerHTML = ``

生成的 HTML 變?yōu)?/p>

由于在 .normal 中 composes 了 .base,編譯后會(huì) normal 會(huì)變成兩個(gè) class。

composes 還可以組合外部文件中的樣式。

/* settings.css */
.primary-color {
  color: #f40;
}

/* components/Button.css */
.base { /* 所有通用的樣式 */ }

.primary {
  composes: base;
  composes: $primary-color from "./settings.css";
  /* primary 其它樣式 */
}

對(duì)于大多數(shù)項(xiàng)目,有了 composes 后已經(jīng)不再需要 Sass/Less/PostCSS。但如果你想用的話(huà),由于 composes 不是標(biāo)準(zhǔn)的 CSS 語(yǔ)法,編譯時(shí)會(huì)報(bào)錯(cuò)。就只能使用預(yù)處理器自己的語(yǔ)法來(lái)做樣式復(fù)用了。

class 命名技巧

CSS Modules 的命名規(guī)范是從 BEM 擴(kuò)展而來(lái)。BEM 把樣式名分為 3 個(gè)級(jí)別,分別是:

Block:對(duì)應(yīng)模塊名,如 Dialog

Element:對(duì)應(yīng)模塊中的節(jié)點(diǎn)名 Confirm Button

Modifier:對(duì)應(yīng)節(jié)點(diǎn)相關(guān)的狀態(tài),如 disabled、highlight

綜上,BEM 最終得到的 class 名為 dialog__confirm-button--highlight。使用雙符號(hào) __-- 是為了和區(qū)塊內(nèi)單詞間的分隔符區(qū)分開(kāi)來(lái)。雖然看起來(lái)有點(diǎn)奇怪,但 BEM 被非常多的大型項(xiàng)目和團(tuán)隊(duì)采用。我們實(shí)踐下來(lái)也很認(rèn)可這種命名方法。

CSS Modules 中 CSS 文件名恰好對(duì)應(yīng) Block 名,只需要再考慮 Element 和 Modifier。BEM 對(duì)應(yīng)到 CSS Modules 的做法是:

/* .dialog.css */
.ConfirmButton--disabled {
}

你也可以不遵循完整的命名規(guī)范,使用 camelCase 的寫(xiě)法把 Block 和 Modifier 放到一起:

/* .dialog.css */
.disabledConfirmButton {
}
如何實(shí)現(xiàn)CSS,JS變量共享

上面提到的 :export 關(guān)鍵字可以把 CSS 中的 變量輸出到 JS 中。下面演示如何在 JS 中讀取 Sass 變量:

/* config.scss */
$primary-color: #f40;

:export {
  primaryColor: $primary-color;
}
/* app.js */
import style from "config.scss";

// 會(huì)輸出 #F40
console.log(style.primaryColor);
CSS Modules 使用技巧

CSS Modules 是對(duì)現(xiàn)有的 CSS 做減法。為了追求簡(jiǎn)單可控,作者建議遵循如下原則:

不使用選擇器,只使用 class 名來(lái)定義樣式

不層疊多個(gè) class,只使用一個(gè) class 把所有樣式定義好

所有樣式通過(guò) composes 組合來(lái)實(shí)現(xiàn)復(fù)用

不嵌套

上面兩條原則相當(dāng)于削弱了樣式中最靈活的部分,初使用者很難接受。第一條實(shí)踐起來(lái)難度不大,但第二條如果模塊狀態(tài)過(guò)多時(shí),class 數(shù)量將成倍上升。

一定要知道,上面之所以稱(chēng)為建議,是因?yàn)?CSS Modules 并不強(qiáng)制你一定要這么做。聽(tīng)起來(lái)有些矛盾,由于多數(shù) CSS 項(xiàng)目存在深厚的歷史遺留問(wèn)題,過(guò)多的限制就意味著增加遷移成本和與外部合作的成本。初期使用中肯定需要一些折衷。幸運(yùn)的是,CSS Modules 這點(diǎn)做的很好:

如果我對(duì)一個(gè)元素使用多個(gè) class 呢?

沒(méi)問(wèn)題,樣式照樣生效。

如何我在一個(gè) style 文件中使用同名 class 呢?

沒(méi)問(wèn)題,這些同名 class 編譯后雖然可能是隨機(jī)碼,但仍是同名的。

如果我在 style 文件中使用了 id 選擇器,偽類(lèi),標(biāo)簽選擇器等呢?
沒(méi)問(wèn)題,所有這些選擇器將不被轉(zhuǎn)換,原封不動(dòng)的出現(xiàn)在編譯后的 css 中。也就是說(shuō) CSS Modules 只會(huì)轉(zhuǎn)換 class 名相關(guān)樣式。

但注意,上面 3 個(gè)“如果”盡量不要發(fā)生。

CSS Modules 結(jié)合 React 實(shí)踐

className 處直接使用 css 中 class 名即可。

/* dialog.css */
.root {}
.confirm {}
.disabledConfirm {}
import classNames from "classnames";
import styles from "./dialog.css";

export default class Dialog extends React.Component {
  render() {
    const cx = classNames({
      [styles.confirm]: !this.state.disabled,
      [styles.disabledConfirm]: this.state.disabled
    });

    return 
Confirm ...
} }

注意,一般把組件最外層節(jié)點(diǎn)對(duì)應(yīng)的 class 名稱(chēng)為 root。這里使用了 classnames 庫(kù)來(lái)操作 class 名。
如果你不想頻繁的輸入 styles.**,可以試一下 react-css-modules,它通過(guò)高階函數(shù)的形式來(lái)避免重復(fù)輸入 styles.**

CSS Modules 結(jié)合歷史遺留項(xiàng)目實(shí)踐

好的技術(shù)方案除了功能強(qiáng)大炫酷,還要能做到現(xiàn)有項(xiàng)目能平滑遷移。CSS Modules 在這一點(diǎn)上表現(xiàn)的非常靈活。

外部如何覆蓋局部樣式

當(dāng)生成混淆的 class 名后,可以解決命名沖突,但因?yàn)闊o(wú)法預(yù)知最終 class 名,不能通過(guò)一般選擇器覆蓋。我們現(xiàn)在項(xiàng)目中的實(shí)踐是可以給組件關(guān)鍵節(jié)點(diǎn)加上 data-role 屬性,然后通過(guò)屬性選擇器來(lái)覆蓋樣式。

// dialog.js
  return 
Confirm ...
// dialog.css
[data-role="dialog-root"] {
  // override style
}

因?yàn)?CSS Modules 只會(huì)轉(zhuǎn)變類(lèi)選擇器,所以這里的屬性選擇器不需要添加 :global

如何與全局樣式共存

前端項(xiàng)目不可避免會(huì)引入 normalize.css 或其它一類(lèi)全局 css 文件。使用 Webpack 可以讓全局樣式和 CSS Modules 的局部樣式和諧共存。下面是我們項(xiàng)目中使用的 webpack 部分配置代碼:

module: {
  loaders: [{
    test: /.jsx?$/,
    loader: "babel"
  }, {
    test: /.scss$/,
    exclude: path.resolve(__dirname, "src/styles"),
    loader: "style!css?modules&localIdentName=[name]__[local]!sass?sourceMap=true"
  }, {
    test: /.scss$/,
    include: path.resolve(__dirname, "src/styles"),
    loader: "style!css!sass?sourceMap=true"
  }]
}
/* src/app.js */
import "./styles/app.scss";
import Component from "./view/Component"

/* src/views/Component.js */
// 以下為組件相關(guān)樣式
import "./Component.scss";

目錄結(jié)構(gòu)如下:

src
├── app.js
├── styles
│   ├── app.scss
│   └── normalize.scss
└── views
    ├── Component.js
    └── Component.scss

這樣所有全局的樣式都放到 src/styles/app.scss 中引入就可以了。其它所有目錄包括 src/views 中的樣式都是局部的。

總結(jié)

CSS Modules 很好的解決了 CSS 目前面臨的模塊化難題。支持與 Sass/Less/PostCSS 等搭配使用,能充分利用現(xiàn)有技術(shù)積累。同時(shí)也能和全局樣式靈活搭配,便于項(xiàng)目中逐步遷移至 CSS Modules。CSS Modules 的實(shí)現(xiàn)也屬輕量級(jí),未來(lái)有標(biāo)準(zhǔn)解決方案后可以低成本遷移。如果你的產(chǎn)品中正好遇到類(lèi)似問(wèn)題,非常值得一試。

原發(fā)于知乎專(zhuān)欄 http://zhuanlan.zhihu.com/purerender/20495964

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

轉(zhuǎn)載請(qǐng)注明本文地址:http://m.specialneedsforspecialkids.com/yun/116377.html

相關(guān)文章

  • 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
  • 3月份前端資源分享

    摘要:面試如何防騙一份優(yōu)秀的前端開(kāi)發(fā)工程師簡(jiǎn)歷是怎么樣的作為,有哪些一般人我都告訴他,但是他都不聽(tīng)的忠告如何面試前端工程師 更多資源請(qǐng)Star:https://github.com/maidishike... 文章轉(zhuǎn)自:https://github.com/jsfront/mo... 3月份前端資源分享 1. Javascript 使用judge.js做信息判斷 javascript...

    nanchen2251 評(píng)論0 收藏0
  • CSS Modules

    摘要:為什么引入全局樣式?jīng)_突進(jìn)行打包時(shí),將所有文件導(dǎo)入到入口文件中,樣式也會(huì)統(tǒng)一加載到入口中,根據(jù)的規(guī)則,后面的樣式會(huì)覆蓋掉前面的樣式聲明,造成全局樣式的覆蓋問(wèn)題。 CSS Modules 為什么引入CSS Modules (1)全局樣式?jīng)_突 webpack進(jìn)行打包時(shí),將所有js文件導(dǎo)入到入口App.js文件中,樣式也會(huì)統(tǒng)一加載到入口中,根據(jù)css的layout規(guī)則,后面的樣式會(huì)覆蓋掉前...

    gecko23 評(píng)論0 收藏0
  • CSS Modules

    摘要:為什么引入全局樣式?jīng)_突進(jìn)行打包時(shí),將所有文件導(dǎo)入到入口文件中,樣式也會(huì)統(tǒng)一加載到入口中,根據(jù)的規(guī)則,后面的樣式會(huì)覆蓋掉前面的樣式聲明,造成全局樣式的覆蓋問(wèn)題。 CSS Modules 為什么引入CSS Modules (1)全局樣式?jīng)_突 webpack進(jìn)行打包時(shí),將所有js文件導(dǎo)入到入口App.js文件中,樣式也會(huì)統(tǒng)一加載到入口中,根據(jù)css的layout規(guī)則,后面的樣式會(huì)覆蓋掉前...

    wangdai 評(píng)論0 收藏0
  • React 入門(mén)實(shí)

    摘要:更多相關(guān)介紹請(qǐng)看這特點(diǎn)僅僅只是虛擬最大限度減少與的交互類(lèi)似于使用操作單向數(shù)據(jù)流很大程度減少了重復(fù)代碼的使用組件化可組合一個(gè)組件易于和其它組件一起使用,或者嵌套在另一個(gè)組件內(nèi)部。在使用后,就變得很容易維護(hù),而且數(shù)據(jù)流非常清晰,容易解決遇到的。 歡迎移步我的博客閱讀:《React 入門(mén)實(shí)踐》 在寫(xiě)這篇文章之前,我已經(jīng)接觸 React 有大半年了。在初步學(xué)習(xí) React 之后就正式應(yīng)用到項(xiàng)...

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

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

0條評(píng)論

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