>

CSS Modules 详解及 React 中实施

- 编辑:至尊游戏网站 -

CSS Modules 详解及 React 中实施

CSS Modules 详解及 React 中实践

2016/01/18 · CSS · CSS Modules, React

原稿出处: pure render - camsong   

至尊游戏网站 1

CSS 是前边贰个领域中前行最慢的一块。由于 ES二零一五/二〇一四 的马上广泛和 Babel/Webpack 等工具的迅猛发展,CSS 被远远甩在了后面,慢慢造成大型项目工程化的痛点。也变为了前面一个走向绝望模块化前必需消除的难点。

CSS 模块化的施工方案有成都百货上千,但第风度翩翩有两类。豆蔻年华类是深透放任 CSS,使用 JS 或 JSON 来写样式。至尊游戏网站,Radium,jsxstyle,react-style 属于这蒸蒸日上类。优点是能给 CSS 提供 JS 一样强盛的模块化本事;劣势是无法运用成熟的 CSS 预管理器(或后Computer) Sass/Less/PostCSS,:hover:active 伪类管理起来复杂。另风姿洒脱类是还是使用 CSS,但利用 JS 来处理体制依赖,代表是 CSS Modules。CSS Modules 能最大化地组合现有 CSS 生态和 JS 模块化手艺,API 简洁到大概零就学开销。发表时依然编写翻译出单身的 JS 和 CSS。它并不依附于 React,只要您选用 Webpack,可以在 Vue/Angular/jQuery 中利用。是自个儿觉着当下最棒的 CSS 模块解决决方案。近日在项目中山高校量施用,上边具体享受下试行中的细节和设法。

 

CSS Modules 入门及 React 中实践

2017/03/25 · CSS · React

初藳出处: AlloyTeam   

CSS 模块化碰着了什么样难点?

CSS 模块化主要的是要化解好八个难点:CSS 样式的导入和导出。灵活按需导入以便复用代码;导出时要力所能致遮掩其间成效域,防止导致全局污染。Sass/Less/PostCSS 等后续试图减轻 CSS 编制程序技艺弱的题目,结果它们做的也真正美丽,但那并未减轻模块化最重视的题目。推文(Tweet)技术员 Vjeux 首先抛出了 React 开荒中境遇的后生可畏各样 CSS 相关难题。加上作者个人的观点,计算如下:

  1. 大局污染

CSS 使用全局选取器机制来设置样式,优点是有益重写样式。劣势是享有的样式皆以全局生效,样式或许被张冠李戴覆盖,因而发生了要命难看的 !important,甚至 inline !important 和复杂的[分选器权重计数表](Selectors Level 3),提升犯错可能率和行使资金。Web Components 标准中的 Shadow DOM 能通透到底消除这几个难点,但它的做法有一点点极端,样式深透局地化,形成外部不可能重写样式,损失了灵活性。

  1. 取名混乱

 

鉴于全局污染的标题,多个人联合签名开荒时为了制止样式冲突,采纳器越来越复杂,轻松变成分裂的命名风格,很难统如日方升。样式变多后,命老将特别混乱。

  1. 依附于管理不通透到底

零件应该相互独立,引进二个零件时,应该只引进它所须求的 CSS 样式。但最近的做法是除了要引进 JS,还要再引进它的 CSS,何况 Saas/Less 很难实现对各类组件都编写翻译出单身的 CSS,引进全部模块的 CSS 又导致浪费。JS 的模块化已经极度干练,纵然能让 JS 来保管 CSS 依赖是很好的消除办法。Webpack 的 css-loader 提供了这种力量。

  1. 望眼欲穿分享变量

复杂组件要利用 JS 和 CSS 来共同管理体制,就能够招致有个别变量在 JS 和 CSS 中冗余,Sass/PostCSS/CSS 等都不提供跨 JS 和 CSS 分享变量这种技艺。

  1. 代码压缩不干净

是因为活动端互联网的不鲜明性,现在对 CSS 压缩已经到了变态的程度。非常多压缩工具为了节省一个字节会把 ’16px’ 转成 ‘1pc’。但对相当短的 class 名却不可能,力没有用到刀刃上。

上边的难题借使只凭 CSS 自个儿是敬谢不敏消除的,若是是经过 JS 来治本 CSS 就很好消除,因而 Vjuex 给出的消除方案是完全的 CSS in JS,但这一定于完全放任CSS,在 JS 中以 Object 语法来写 CSS,推断刚见到的同伴都吃惊了。直到出现了 CSS Modules。

 

写在近些日子

读文先看此图,能先有个大约概念:

至尊游戏网站 2

阅读本文必要 11m 24s。

CSS Modules 模块化方案

至尊游戏网站 3

CSS Modules 内部通过 [ICSS](css-modules/icss · GitHub) 来缓慢解决体制导入和导出那七个难题。分别对应 :import:export 四个新扩充的伪类。

JavaScript

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

1
2
3
4
5
6
7
8
:import("path/to/dep.css") {
  localAlias: keyFromDep;
  /* ... */
}
:export {
  exportedKey: exportedValue;
  /* ... */
}

 

但间接选用那多个至关心器重要字编制程序太辛苦,实际项目中比较少会直接动用它们,大家必要的是用 JS 来保管 CSS 的力量。结合 Webpack 的 css-loader 后,就足以在 CSS 中定义样式,在 JS 中程导弹入。
启用 CSS Modules

JavaScript

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

1
2
// webpack.config.js
css?modules&localIdentName=[name]__[local]-[hash:base64:5]

加上 modules 即为启用,localIdentName 是设置生成样式的命名准绳。

JavaScript

/* components/Button.css */ .normal { /* normal 相关的有所样式 */ } .disabled { /* disabled 相关的具备样式 */ }

1
2
3
/* components/Button.css */
.normal { /* normal 相关的所有样式 */ }
.disabled { /* disabled 相关的所有样式 */ }

JavaScript

// components/Button.js import styles from './Button.css'; console.log(styles); buttonElem.outerHTML = `<button class=${styles.normal}>Submit</button>`

1
2
3
4
// components/Button.js
import styles from './Button.css';
console.log(styles);
buttonElem.outerHTML = `<button class=${styles.normal}>Submit</button>`

生成的 HTML 是

<button class="button--normal-abc53">Submit</button>

1
<button class="button--normal-abc53">Submit</button>

 

注意到 button--normal-abc53 是 CSS Modules 按照 localIdentName 自动生成的 class 名。此中的 abc53 是根据给定算法生成的系列码。经过那样模糊管理后,class 名基本正是独步一时的,大大减少了项目中样式覆盖的概率。同不经常候在生产景况下修改准绳,生成更加短的 class 名,能够增进 CSS 的压缩率。

上例中 console 打字与印刷的结果是:

JavaScript

Object { normal: 'button--normal-abc53', disabled: 'button--disabled-def886', }

1
2
3
4
Object {
  normal: 'button--normal-abc53',
  disabled: 'button--disabled-def886',
}

CSS Modules 对 CSS 中的 class 名都做了拍卖,使用对象来保存原 class 和歪曲后 class 的照望关系。

经过那一个轻易的拍卖,CSS Modules 完结了以下几点:

  • 具备样式都以 local 的,化解了命名冲突和大局污染难题
  • class 名生成准则配置灵活,能够此来减弱 class 名
  • 只需援引组件的 JS 就能够消除组件全部的 JS 和 CSS
  • 反之亦然是 CSS,大约 0 学习成本

体制默许局地

使用了 CSS Modules 后,就一定于给各种 class 名外加加了一个 :local,以此来兑现样式的局部化,如若您想切换到全局格局,使用相应的 :global

:local:global 的分别是 CSS Modules 只会对 :local 块的 class 样式做 localIdentName 准则管理,:global 的体制编写翻译后不改变。

JavaScript

.normal { color: green; } /* 以上与下部等价 */ :local(.normal) { color: green; } /* 定义全局样式 */ :global(.btn) { color: red; } /* 定义五个全局样式 */ :global { .link { color: green; } .box { color: yellow; } }

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
.normal {
  color: green;
}
 
/* 以上与下面等价 */
:local(.normal) {
  color: green;
}
 
/* 定义全局样式 */
:global(.btn) {
  color: red;
}
 
/* 定义多个全局样式 */
:global {
  .link {
    color: green;
  }
  .box {
    color: yellow;
  }
}

Compose 来组合样式

对于样式复用,CSS Modules 只提供了唯风姿罗曼蒂克的法子来拍卖:composes 组合

JavaScript

/* components/Button.css */ .base { /* 全部通用的体裁 */ } .normal { composes: base; /* normal 此外样式 */ } .disabled { composes: base; /* disabled 此外样式 */ }

1
2
3
4
5
6
7
8
9
10
11
12
/* components/Button.css */
.base { /* 所有通用的样式 */ }
 
.normal {
  composes: base;
  /* normal 其它样式 */
}
 
.disabled {
  composes: base;
  /* disabled 其它样式 */
}

JavaScript

import styles from './Button.css'; buttonElem.outerHTML = `<button class=${styles.normal}>Submit</button>`

1
2
3
import styles from './Button.css';
 
buttonElem.outerHTML = `<button class=${styles.normal}>Submit</button>`

生成的 HTML 变为

<button class="button--base-fec26 button--normal-abc53">Submit</button>

1
<button class="button--base-fec26 button--normal-abc53">Submit</button>

由于在 .normal 中 composes 了 .base,编写翻译后会 normal 会产生两个class。

composes 还足以结合外界文件中的样式。

JavaScript

/* settings.css */ .primary-color { color: #f40; } /* components/Button.css */ .base { /* 全部通用的体制 */ } .primary { composes: base; composes: primary-color from './settings.css'; /* primary 另外样式 */ }

1
2
3
4
5
6
7
8
9
10
11
12
13
/* settings.css */
.primary-color {
  color: #f40;
}
 
/* components/Button.css */
.base { /* 所有通用的样式 */ }
 
.primary {
  composes: base;
  composes: primary-color from './settings.css';
  /* primary 其它样式 */
}

 

对此超过半数连串,有了 composes 后早已不再供给Sass/Less/PostCSS。但如若您想用的话,由于 composes 不是专门的学业的 CSS 语法,编写翻译时会报错。就只好利用预管理器自个儿的语法来做样式复用了。
class 命名工夫

CSS Modules 的命名标准是从 BEM 扩充而来。BEM 把体制名分为 3 个品级,分别是:

  • Block:对应模块名,如 Dialog
  • Element:对应模块中的节点名 Confirm Button
  • Modifier:对应节点相关的情景,如 disabled、highlight

综上,BEM 最后获得的 class 名称为 dialog__confirm-button--highlight。使用双标识 __-- 是为着和区块内单词间的相间符区分开来。固然看起来有个别匪夷所思,但 BEM 被那多少个多的大型项目和团伙利用。大家奉行下来也很明确这种命名方式。

CSS Modules 中 CSS 文件名刚刚对应 Block 名,只须要再怀念 Element 和 Modifier。BEM 对应到 CSS Modules 的做法是:

JavaScript

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

1
2
3
4
/* .dialog.css */
.ConfirmButton--disabled {
  /* ... */
}

你也足以不相信守完全的命名标准,使用 camelCase 的写法把 Block 和 Modifier 放到一同:

JavaScript

/* .dialog.css */ .disabledConfirmButton { }

1
2
3
/* .dialog.css */
.disabledConfirmButton {
}

如何促成CSS,JS变量分享

注:CSS Modules 中平素不改变量的定义,这里的 CSS 变量指的是 Sass 中的变量。

地点提到的 :export 关键字能够把 CSS 中的 变量输出到 JS 中。下边演示如何在 JS 中读取 Sass 变量:

JavaScript

/* config.scss */ $primary-color: #f40; :export { primaryColor: $primary-color; }

1
2
3
4
5
6
/* config.scss */
$primary-color: #f40;
 
:export {
  primaryColor: $primary-color;
}

 

JavaScript

/* app.js */ import style from 'config.scss'; // 会输出 #F40 console.log(style.primaryColor);

1
2
3
4
5
/* app.js */
import style from 'config.scss';
 
// 会输出 #F40
console.log(style.primaryColor);

CSS Modules介绍

CSS Modules是什么事物吗?首先,让我们从官方文书档案入手:
GitHub – css-modules/css-modules: Documentation about css-modules

A CSS Module is a CSS file in which all class names and animation names are scoped locally by default. CSS模块便是兼具的类名都唯有局地效率域的CSS文件。

进而CSS Modules既不是法定正规,亦非浏览器的性状,而是在营造步骤(举例利用Webpack或Browserify)中对CSS类名选用器限定成效域的豆蔻梢头种办法(通过hash完毕类似于命名空间的办法)。

It doesn’t really matter in the end (although shorter class names mean shorter stylesheets) because the point is that they are dynamically generated, unique, and mapped to the correct styles.在选用CSS模块时,类名是动态变化的,唯后生可畏的,并准确对应到源文件中的各类类的体制。

那也是兑现样式成效域的原理。它们被界定在一定的模板里。比如大家在buttons.js里引入buttons.css文件,并使用.btn的体制,在其余零件里是不会被.btn影响的,除非它也引进了buttons.css.

可大家是出于什么样指标把CSS和HTML文件搞得这么零碎呢?我们为啥要动用CSS模块呢?

CSS Modules 使用技艺

CSS Modules 是对现有的 CSS 做减法。为了追求**简言之可控**,小编提出依据如下原则:

  • 不应用采用器,只行使 class 名来定义样式
  • 不层叠三个 class,只利用八个 class 把持有样式定义好
  • 不嵌套
  • 使用 composes 组合来贯彻复用

下面两条准则相当于削弱了体制中最灵敏的有的,初使用者很难选拔。第一条实行起来难度比较小,但第二条假设模块状态过多时,class 数量将加倍上涨。

必然要了解,上边之所以称之为提出,是因为 CSS Modules 并不强制你分明要那样做。听上去有一点点水火不容,由于大多数 CSS 项目设有深厚的历史遗留难题,过多的界定就象征扩大迁移开销和与表面合营的本金。初期使用中料定须要某些低头。幸运的是,CSS Modules 那一点做的很好:

1. 生机盎然旦本身对八个因素运用两个 class 呢?

没难题,样式还是生效。

2. 怎么着自个儿在贰个 style 文件中应用同名 class 呢?

没难题,这么些同名 class 编写翻译后虽说恐怕是随机码,但仍然是同名的。

3. 万新闯祸物正在如日中天本人在 style 文件中动用了 id 选拔器,伪类,标签选取器等呢?

没难点,全体那几个采取器将不被转移,未有丝毫改换的出现在编写翻译后的 css 中。也正是说 CSS Modules 只会转变 class 名相关样式。

但注意,上面 3 个“假使”尽量不要发生

缘何我们供给CSS模块化

CSS Modules 结合 React 实践

className 处直接运用 css 中 class 名即可。

JavaScript

.root {} .confirm {} .disabledConfirm {}

1
2
3
.root {}
.confirm {}
.disabledConfirm {}

import classNames from 'classnames'; import styles from './dialog.css'; export default class Dialog extends React.Component { render() { const cx = classNames({ confirm: !this.state.disabled, disabledConfirm: this.state.disabled }); return <div className={styles.root}> <a className={styles.disabledConfirm}>Confirm</a> ... </div> } }

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
import classNames from 'classnames';
import styles from './dialog.css';
 
export default class Dialog extends React.Component {
  render() {
    const cx = classNames({
      confirm: !this.state.disabled,
      disabledConfirm: this.state.disabled
    });
 
    return <div className={styles.root}>
      <a className={styles.disabledConfirm}>Confirm</a>
      ...
    </div>
  }
}

小心,日常把组件最外层节点对应的 class 名字为 root。这里运用了 [classnames](https://www.npmjs.com/package/classnames) 库来操作 class 名。

风度翩翩经你不想频繁的输入 styles.**,能够试一下 [react-css-modules](gajus/react-css-modules · GitHub),它通过高阶函数的花样来制止重新输入 styles.**

CSS Modules 结合历史遗留项目推行

好的手艺方案除了功能强盛炫人眼目,还要能成就现成项目能平滑迁移。CSS Modules 在此或多或少上海展览中心现的特别灵活。

表面怎么样覆盖局地样式

当生成混淆的 class 名后,能够消除命名冲突,但因为无法预见最后 class 名,不可能经过经常接收器覆盖。大家未来项目中的实践是足以给组件关键节点加上 data-role 属性,然后通过质量选取器来覆盖样式。

// dialog.js return <div className={styles.root} data-role='dialog-root'> <a className={styles.disabledConfirm} data-role='dialog-confirm-btn'>Confirm</a> ... </div>

1
2
3
4
5
// dialog.js
  return <div className={styles.root} data-role='dialog-root'>
      <a className={styles.disabledConfirm} data-role='dialog-confirm-btn'>Confirm</a>
      ...
  </div>

 

JavaScript

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

1
2
3
4
/* dialog.css */
[data-role="dialog-root"] {
  // override style
}

因为 CSS Modules 只会生成类选取器,所以这里的习性选拔器没有必要增加 :global

怎么与全局样式共存

前者项目不可防止会引进 normalize.css 或另外风流浪漫类全局 css 文件。使用 Webpack 能够让全局样式和 CSS Modules 的片段样式和睦共存。上面是大家项目中动用的 webpack 部总局署代码:

JavaScript

文章权归作者全部。 商业转发请联系小编得到授权,非商业转发请注明出处。 笔者:camsong 链接: 来源:知乎 // webpack.config.js 局部 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' }] }

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
著作权归作者所有。
商业转载请联系作者获得授权,非商业转载请注明出处。
作者:camsong
链接:http://zhuanlan.zhihu.com/purerender/20495964
来源:知乎
 
// webpack.config.js 局部
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'
  }]
}

JavaScript

/* src/app.js */ import './styles/app.scss'; import Component from './view/Component' /* src/views/Component.js */ // 以下为组件相关样式 import './Component.scss';

1
2
3
4
5
6
7
/* src/app.js */
import './styles/app.scss';
import Component from './view/Component'
 
/* src/views/Component.js */
// 以下为组件相关样式
import './Component.scss';

目录结构如下:

JavaScript

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

1
2
3
4
5
6
7
8
src
├── app.js
├── styles
│   ├── app.scss
│   └── normalize.scss
└── views
    ├── Component.js
    └── Component.scss

如此那般全体全局的样式都放到 src/styles/app.scss 中引进就足以了。别的具备目录富含 src/views 中的样式都是部分的。

CSS全局功效域难题

CSS的准则都是全局的,任何叁个零部件的体制法则,都对总体页面有效。相信写css的人都会超过样式冲突(污染)的主题材料。

于是乎通常这么做(作者都做过):
* class命名写长一点呢,减少冲突的概率
* 加个父成分的选择器,限制范围
* 重新命名个class吧,相比保险

所以亟待化解的标题正是css局地成效域制止全局样式冲突(污染)的主题素材

总结

CSS Modules 很好的消除了 CSS 近来边临的模块化难点。援助与 Sass/Less/PostCSS 等搭配使用,能充裕利用现成本领积淀。同偶尔间也能和全局样式灵活搭配,便于项目中渐渐搬迁至 CSS Modules。CSS Modules 的落到实处也属轻量级,未来有标准实施方案后得以低本钱迁移。借使你的制品中恰恰碰见类似主题素材,极度值得风流罗曼蒂克试。

1 赞 2 收藏 评论

至尊游戏网站 4

JS CSS不能够分享变量

复杂组件要使用 JS 和 CSS 来共同管理体制,就能够导致有个别变量在 JS 和 CSS 中冗余,CSS预管理器/后甩卖器 等都不提供跨 JS 和 CSS 分享变量这种本领。

虎背熊腰并且扩大方便的CSS

用作有追求的技术员,编写强壮何况扩大方便的CSS一直是大家的靶子。那么什么样定义强健并且扩充方便?有八当中心:

  • 面向组件 – 处理 UI 复杂性的顶尖实施就是将 UI 分割成贰个个的小组件 Locality_of_reference 。假设你正在使用多个创建的框架,JavaScript 方面就将原生扶助(组件化)。譬如,React 就慰勉中度组件化和细分。我们期待有贰个 CSS 框架结构去相称。
  • 沙箱化(Sandboxed) – 假使二个零件的体裁会对别的零件产生不须求以致敬外的震慑,那么将 UI 分割成组件并不曾什么用。就那上面来讲,CSS的全局意义域会给您变成担当。
  • 方便人民群众 – 我们想要全体好的东西,並且不想产生更加多的职业。也便是说,我们不想因为使用这几个架构而让我们的开拓者体验变得更糟。或者的话,大家想开采者体验变得更加好。

CSS模块化方案分类

CSS 模块化的建设方案有相当多,但关键有三类。

CSS 命名约定

标准化CSS的模块化解决方案(比如BEM BEM — Block Element Modifier,OOCSS,AMCSS,SMACSS,SUITCSS)
但存在以下难点:
* JS CSS之间仍旧未有开采变量和选择器等
* 复杂的命名

CSS in JS

干净舍弃 CSS,用 JavaScript 写 CSS 准绳,并内联样式。 React: CSS in JS // Speaker Deck。Radium,react-style 属于那风姿浪漫类。但存在以下难题:
* 无法利用伪类,媒体询问等
* 样式代码也会产出大批量重复。
* 无法使用成熟的 CSS 预管理器(或后计算机)

行使JS 来保管体制模块

使用JS编译原生的CSS文件,使其具备模块化的力量,代表是 CSS Modules GitHub – css-modules/css-modules: Documentation about css-modules 。

CSS Modules 能最大化地构成现成 CSS 生态(预管理器/后Computer等)和 JS 模块化才干,差十分的少零学学习开销用。只要你采用Webpack,能够在别的项目中应用。是小编以为当前最棒的 CSS 模块化解决方案。

CSS Modules 使用教程

启用 CSS Modules

JavaScript

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

1
2
// webpack.config.js
css?modules&localIdentName=[name]__[local]-[hash:base64:5]

加上 modules 即为启用,localIdentName 是设置生成样式的命名法规。

CSS

/* components/Button.css */ .normal { /* normal 相关的有所样式 */ }

1
2
/* components/Button.css */
.normal { /* normal 相关的所有样式 */ }

JavaScript

// components/Button.js import styles from './Button.css'; console.log(styles); buttonElem.outerHTML = `<button class=${styles.normal}>Submit</button>`

1
2
3
4
// components/Button.js
import styles from './Button.css';
console.log(styles);
buttonElem.outerHTML = `<button class=${styles.normal}>Submit</button>`

生成的 HTML 是

XHTML

<button class="button--normal-abc53">Submit</button>

1
<button class="button--normal-abc53">Submit</button>

注意到 button--normal-abc53 是 CSS Modules 按照 localIdentName 自动生成的 class 名。个中的abc53 是根据给定算法生成的体系码。经过这样模糊管理后,class 名基本就是唯如火如荼的,大大降低了花色中样式覆盖的可能率。同期在生养条件下修改法则,生成更加短的 class 名,能够提升 CSS 的压缩率。

上例中 console 打字与印刷的结果是:

CSS

Object {   normal: 'button--normal-abc53',   disabled: 'button--disabled-def886', }

1
2
3
4
Object {
  normal: 'button--normal-abc53',
  disabled: 'button--disabled-def886',
}

CSS Modules 对 CSS 中的 class 名都做了拍卖,使用对象来保存原 class 和混淆后 class 的应和关系。

透过那几个轻松的拍卖,CSS Modules 完结了以下几点:
* 全部样式都以一些效率域 的,消除了全局污染难题
* class 名生成法则配置灵活,能够此来压缩 class 名
* 只需引用组件的 JS 就会消除组件全数的 JS 和 CSS
* 还是是 CSS,差非常的少 0 学习花费

CSS Modules 在React中的实施

那么大家在React中怎么选取?

手动援引化解

className 处直接利用 css 中 class 名即可。

JavaScript

import React from 'react'; import styles from './table.css';   export default class Table extends React.Component {     render () {         return <div className={styles.table}>             <div className={styles.row}>             </div>         </div>;     } }

1
2
3
4
5
6
7
8
9
10
11
import React from 'react';
import styles from './table.css';
 
export default class Table extends React.Component {
    render () {
        return <div className={styles.table}>
            <div className={styles.row}>
            </div>
        </div>;
    }
}

渲染出来的零部件出来

XHTML

<div class="table__table___32osj">     <div class="table__row___2w27N">     </div> </div>

1
2
3
4
<div class="table__table___32osj">
    <div class="table__row___2w27N">
    </div>
</div>

react-css-modules

假定您不想频仍的输入 styles.**,有一个 GitHub – gajus/react-css-modules: Seamless mapping of class names to CSS modules inside of React components.,它通过高阶函数的款式来扭转className,不过不引入应用,后文仲提到。

API也很简短,给组件外包三个CSSModules就可以。

JavaScript

import React from 'react'; import CSSModules from 'react-css-modules'; import styles from './table.css';   class Table extends React.Component {     render () {         return <div styleName='table'>         </div>;     } }   export default CSSModules(Table, styles);

1
2
3
4
5
6
7
8
9
10
11
12
import React from 'react';
import CSSModules from 'react-css-modules';
import styles from './table.css';
 
class Table extends React.Component {
    render () {
        return <div styleName='table'>
        </div>;
    }
}
 
export default CSSModules(Table, styles);

只是那样我们得以看出,它是急需周转时的信任性,并且须求在运营时才得到className,质量损耗大,那么有未有便利又就如无损的点子吗?答案是有个别,使用babel插件babel-plugin-react-css-modulesGitHub – gajus/babel-plugin-react-css-modules: Transforms styleName to className using compile time CSS module resolution. 把className获取前置到编写翻译阶段。

babel-plugin-react-css-modules

babel-plugin-react-css-modules 能够完毕应用styleName天性自动加载CSS模块。大家因此该babel插件来进展语法树分析并末了生成className

来看看组件的写法,现在你只供给把className换成styleName就能够得到CSS局地功效域的力量了,是还是不是特别容易。

JavaScript

import React from 'react'; import styles from './table.css';   class Table extends React.Component {     render () {         return <div styleName='table'>         </div>;     } }   export default Table;

1
2
3
4
5
6
7
8
9
10
11
import React from 'react';
import styles from './table.css';
 
class Table extends React.Component {
    render () {
        return <div styleName='table'>
        </div>;
    }
}
 
export default Table;

专门的工作原理

那么该babel插件是怎么工作的呢?让大家从官方文书档案入手:

GitHub – gajus/babel-plugin-react-css-modules: Transforms styleName to className using compile time CSS module resolution.

小编不才 ,稍作翻译如下:
1. 创设每一种文件的兼具样式表导入的目录(导入具备.css.scss扩张名的文本)。

  1. 使用postcss 分析相称到的css文件
  2. 遍历全部 JSX 成分注脚
  3. styleName 属性深入分析成匿名和命名的有的css模块援引
  4. 搜求与CSS模块援引相相称的CSS类名称:
    * 如果styleName的值是贰个字符串字面值,生成多少个字符串字面值。
    * 固然是JSXExpressionContainer,在运作时接收helper函数来创设固然styleName的值是二个jSXExpressionContainer, 使用扶持函数([getClassName]在运行时组织className值。
  5. 从要素上移除styleName属性。
    7. 将转换的className累计到存活的className值中(要是不设有则创建className属性)。

运用实例

在成熟的连串中,经常都会用到CSS预处理器可能后Computer。

此间以使用了stylusCSS预管理器为例子,大家来看下如何利用。

  • 设置依赖

Shell

npm install -save-dev sugerss babel-plugin-react-css-modules

1
npm install -save-dev sugerss babel-plugin-react-css-modules
  • 编写Webpack配置
JavaScript

// webpack.config.js module: {   loaders: [{     test: /\.js?$/,
    loader: [['babel-plugin-react-css-modules',{
          generateScopedName:'[name]__[local]',
          filetypes: {               ".styl": "sugerss"            }
     }]]   }, {     test: /\.module.styl$/,     loader:
'style!css?modules&localIdentName=[name]__[local]!styl?sourceMap=true'
  }, {     test: /\.styl$/,     loader:
'style!css!styl?sourceMap=true'   }] }

<table>
<colgroup>
<col style="width: 50%" />
<col style="width: 50%" />
</colgroup>
<tbody>
<tr class="odd">
<td><div class="crayon-nums-content" style="font-size: 13px !important; line-height: 15px !important;">
<div class="crayon-num" data-line="crayon-5b8f6729d9ed4116610999-1">
1
</div>
<div class="crayon-num crayon-striped-num" data-line="crayon-5b8f6729d9ed4116610999-2">
2
</div>
<div class="crayon-num" data-line="crayon-5b8f6729d9ed4116610999-3">
3
</div>
<div class="crayon-num crayon-striped-num" data-line="crayon-5b8f6729d9ed4116610999-4">
4
</div>
<div class="crayon-num" data-line="crayon-5b8f6729d9ed4116610999-5">
5
</div>
<div class="crayon-num crayon-striped-num" data-line="crayon-5b8f6729d9ed4116610999-6">
6
</div>
<div class="crayon-num" data-line="crayon-5b8f6729d9ed4116610999-7">
7
</div>
<div class="crayon-num crayon-striped-num" data-line="crayon-5b8f6729d9ed4116610999-8">
8
</div>
<div class="crayon-num" data-line="crayon-5b8f6729d9ed4116610999-9">
9
</div>
<div class="crayon-num crayon-striped-num" data-line="crayon-5b8f6729d9ed4116610999-10">
10
</div>
<div class="crayon-num" data-line="crayon-5b8f6729d9ed4116610999-11">
11
</div>
<div class="crayon-num crayon-striped-num" data-line="crayon-5b8f6729d9ed4116610999-12">
12
</div>
<div class="crayon-num" data-line="crayon-5b8f6729d9ed4116610999-13">
13
</div>
<div class="crayon-num crayon-striped-num" data-line="crayon-5b8f6729d9ed4116610999-14">
14
</div>
<div class="crayon-num" data-line="crayon-5b8f6729d9ed4116610999-15">
15
</div>
<div class="crayon-num crayon-striped-num" data-line="crayon-5b8f6729d9ed4116610999-16">
16
</div>
<div class="crayon-num" data-line="crayon-5b8f6729d9ed4116610999-17">
17
</div>
<div class="crayon-num crayon-striped-num" data-line="crayon-5b8f6729d9ed4116610999-18">
18
</div>
</div></td>
<td><div class="crayon-pre" style="font-size: 13px !important; line-height: 15px !important; -moz-tab-size:4; -o-tab-size:4; -webkit-tab-size:4; tab-size:4;">
<div id="crayon-5b8f6729d9ed4116610999-1" class="crayon-line">
// webpack.config.js
</div>
<div id="crayon-5b8f6729d9ed4116610999-2" class="crayon-line crayon-striped-line">
module: {
</div>
<div id="crayon-5b8f6729d9ed4116610999-3" class="crayon-line">
  loaders: [{
</div>
<div id="crayon-5b8f6729d9ed4116610999-4" class="crayon-line crayon-striped-line">
    test: /.js?$/,
</div>
<div id="crayon-5b8f6729d9ed4116610999-5" class="crayon-line">
    loader: [['babel-plugin-react-css-modules',{
</div>
<div id="crayon-5b8f6729d9ed4116610999-6" class="crayon-line crayon-striped-line">
          generateScopedName:'[name]__[local]',
</div>
<div id="crayon-5b8f6729d9ed4116610999-7" class="crayon-line">
          filetypes: {
</div>
<div id="crayon-5b8f6729d9ed4116610999-8" class="crayon-line crayon-striped-line">
              &quot;.styl&quot;: &quot;sugerss&quot;
</div>
<div id="crayon-5b8f6729d9ed4116610999-9" class="crayon-line">
           }
</div>
<div id="crayon-5b8f6729d9ed4116610999-10" class="crayon-line crayon-striped-line">
     }]]
</div>
<div id="crayon-5b8f6729d9ed4116610999-11" class="crayon-line">
  }, {
</div>
<div id="crayon-5b8f6729d9ed4116610999-12" class="crayon-line crayon-striped-line">
    test: /.module.styl$/,
</div>
<div id="crayon-5b8f6729d9ed4116610999-13" class="crayon-line">
    loader: 'style!css?modules&amp;localIdentName=[name]__[local]!styl?sourceMap=true'
</div>
<div id="crayon-5b8f6729d9ed4116610999-14" class="crayon-line crayon-striped-line">
  }, {
</div>
<div id="crayon-5b8f6729d9ed4116610999-15" class="crayon-line">
    test: /.styl$/,
</div>
<div id="crayon-5b8f6729d9ed4116610999-16" class="crayon-line crayon-striped-line">
    loader: 'style!css!styl?sourceMap=true'
</div>
<div id="crayon-5b8f6729d9ed4116610999-17" class="crayon-line">
  }]
</div>
<div id="crayon-5b8f6729d9ed4116610999-18" class="crayon-line crayon-striped-line">
}
</div>
</div></td>
</tr>
</tbody>
</table>
  • 组件写法

JavaScript

import React from 'react'; import './table.module.styl';   class Table extends React.Component {     render () {         return <div styleName='table'>         </div>;     } }   export default Table;

1
2
3
4
5
6
7
8
9
10
11
import React from 'react';
import './table.module.styl';
 
class Table extends React.Component {
    render () {
        return <div styleName='table'>
        </div>;
    }
}
 
export default Table;

如上,你可以因而配备Webpack中module.loaders的test路线Webpack-module-loaders-configuration,来区分样式文件是还是不是需求CSS模块化。
搭配sugerss这个postcss插件作为stylus的语法加载器,来支撑babel插件babel-plugin-react-css-modules的语法分析。

末尾我们回过头来看下,大家React组件只要求把className换成styleName,搭配以上营造配置,就能够兑现CSS模块化 。

最后

CSS Modules 很好的减轻了 CSS 近些日子面临的模块化难点。扶植与 CSS管理器搭配使用,能丰硕利用现成手艺积淀。假诺你的成品中正好蒙受类似难点,非常值得后生可畏试。

盼望大家都能写出健康并且可扩张的CSS,以上。

1 赞 2 收藏 评论

至尊游戏网站 5

本文由门户名站发布,转载请注明来源:CSS Modules 详解及 React 中实施