CSS Modules 详解


本文摘自PHP中文网,作者Guanhui,侵删。

层叠样式表

我们知道,css的全名叫做层叠样式表,这个“层叠”到底是什么意思呢?

有一种解释是,如果你先写了一条样式规则(选手1):


1

2

3

.title {

 color: silver;

}

然后又在后边写了一条类似的(选手2):


1

2

3

.title {

 color: gold;

}

因为名字相同,选手2就会和选手1打起来(让你丫冒充我!)。结果是选手2获胜,class名为title的元素,最终的color值为gold。

css里就像这样,随时可能一言不和就发生战争,结果输掉的一方就会被胜利的一方所覆盖。“层叠”一词可以说形象地描述了这个过程。

那么,为什么会有这样的层叠(zhàn zhēng )呢?

css的作用域问题

在javascript里,可以做到这样的搭配:


1

2

3

4

5

6

7

8

var title = "silver";

 

(function(){

 var title = "gold";

 console.log(title); // gold

}());

 

console.log(title); // silver

利用javascript的函数作用域,两位同样名为title的选手可以友好相处。

但回到css里的样式规则,情况就完全不是这么回事了。

css不是程序语言,但如果说要给它加一个作用域的概念的话,那就是:只有全局作用域。

无论分拆为多少个css文件,无论用怎样的方式引入,所有的样式规则都位于同一作用域,只要选择符近似,就有发生覆盖的可能。

减少相互影响的策略

为减少相互影响,避免预料之外的样式覆盖,我们一直以来想过很多办法。

比如你接手一个别人留下来的旧项目,接下来要新增一个标题元素的时候,你会有意识地不去使用.title这样模糊的class名,因为它太容易重名了。最终,你用的名称可能是:


1

2

3

.module-sp-title {

 color: deepskyblue;

}

即使你决定要用.title这个名字,你也会加上包含选择符作为限定:


1

2

3

4

5

6

7

.module-1 .title {

 font-size: 18px;

}

/* ... */

.module-2 .title {

 font-size: 14px;

}

其中.module-1和.module-2的名字应该是唯一的,这样的代码在组件化(模块化)的开发风格里很常见。

此外,一些有名的css理论,如SMACSS,会建议你为所有布局样式使用l-或layout-的前缀,以示区分。

类似的做法还有很多,但归结起来,都是在尝试提供一种合理的命名约定。而合理的命名约定,的确是组织css代码的有效策略。

现在,我们有了新的可用策略,CSS Modules就是其中之一。

技术流的模块化

CSS Modules是一种技术流的组织css代码的策略,它将为css提供默认的局部作用域。

CSS Modules是如何做到的呢?来看一个CSS Modules的简单例子吧。

有这样的一个html元素:


1

<h2 id="example_title" class="title">a title for CSS Modules</h2>

按照普通css的写法,我们可以这样为它添加样式:


1

2

3

.title {

 background-color: snow;

}

现在我们改用CSS Modules。首先,css保持不变。然后,修改html的写法。不再这样直接写html,而是改为在javascript文件里动态添加,这样做(css文件名为main.css):


1

2

3

4

var styles = require("./main.css");

 

var el = document.getElementById("example_title");

el.outerHTML = '<h2 class="' + styles.title + '">a title for CSS Modules</h2>';

咦,require了一个css文件?对的,所以要用到webpack。编译后,html和css会变成这样:

看到这样不太美观的class名你大概就明白了,CSS Modules无法改变css全局作用域的本性,它是依靠动态生成class名这一手段,来实现局部作用域的。显然,这样的class名就可以是唯一的,不管原本的css代码写得有多随便,都可以这样转换得到不冲突的css代码。

模拟的局部作用域也没有关系,它是可靠的。

这个CSS Modules的例子说完了,但你一定跟我最初看到的时候一样有很多问题。

CSS Modules的应用细节

如何启用CSS Modules

“webpack编译css我也用过,怎么我用的时候不长这样?”

一般来说,require一个css文件的写法是:


1

require("./main.css");

但在前面的例子中,用了var styles = require("./main.css");的写法。这就好像是在说,我要这个css文件里的样式是局部的,然后我根据需要自行取用。

在项目里应用CSS Modules有很多方法,目前比较常用的是使用webpack的css-loader。在webpack配置文件里写css-loader?modules就可以开启CSS Modules,例如前面的例子所用的:


1

2

3

4

5

6

module: {

 loaders: [{

  test: /\.css$/,

  loader: 'style!css?modules'

 }]

}

才发现一直用着的css-loader原来有这功能?其实,CSS Modules确实是一个后来才并入css-loader的新功能。

自定义生成的class名

名字都这样了,还怎么调试?”

为css-loader增加localIdentName参数,是可以指定生成的名字。localIdentName的默认值是[hash:base64],一般开发环境建议用类似这样的配置:


1

2

3

4

{

 test: /\.css$/,

 loader: 'style!css?modules&localIdentName=[name]__[local]___[hash:base64:5]'

}

同样应用到前面的例子里,这时候就会变成这样的结果:

这样是不是要有意义多了?

如果是线上环境,可以考虑用更短的名字进一步减小css文件大小。

CSS Modules下的html

(看了前面例子里的el.outerHTML = ...后)

“什么,outerHTML?class名还要拼接?你家html才这么写呢!”

很遗憾,CSS Modules官方的例子,也是这个意思:要使用CSS Modules,必须想办法把变量风格的class名注入到html中。也就是说,html模板系统是必需的,也正是如此,相比普通css的情况,CSS Modules的html写起来要更为费劲。

阅读剩余部分

相关阅读 >>

css中元素的浮动用什么属性

css flex-flow属性怎么用

css outline-offset属性怎么用

css怎么让li强制不换行

css flex布局的优缺点是什么

css box-direction属性怎么用

css a代表什么

怎么在head区域引入css

css描边属性是什么

css animation-delay属性怎么用

更多相关阅读请进入《css》频道 >>




打赏

取消

感谢您的支持,我会继续努力的!

扫码支持
扫码打赏,您说多少就多少

打开支付宝扫一扫,即可进行扫码打赏哦

分享从这里开始,精彩与您同在

评论

管理员已关闭评论功能...