该篇为翻译文章,原文地址为:What are CSS Modules and why do we need them?
我最近一直对CSS Modules比较感兴趣。如果你还没有听说过CSS Modules,那么你可以看看这篇文章。我们将把它放在项目当中来看一下它到底有什么样的作用。如果你对此也很感兴趣,那么后期还会有其它想关文章更新,这篇文章只是一个简单的介绍。
该系列文章目录:
第一部分: CSS Modules是什么东西,我们为什么需要它? (当前)
什么是CSS Modules?
根据官方的这篇介绍,CSS modules也是一些CSS文件,但默认情况下这些CSS文件里的一些class名和动画名等都只在文件本身内起作用(生成局部作用域)。
所以,CSS Modules并不是一个官方发布的一个东西,也不是浏览器内部进行实现的。而是我们在利用一些工具(例如Webpack或Browserify)把文件当中的class名和选择器进行一个”命名空间化”的操作过程。
说了这么多,那么它到底是什么样子的呢?并且为什么要这么做呢?在解答这个问题之前,我们来看下平时是怎么写HTML和CSS的:
首先是一段HTML:
<h1 class="title">An example heading</h1>
然后是CSS:
.title {
background-color: red;
}
只要HTML文件应用了这个CSS文件,那么<h1>
标签的背景色就会变成红色。我们不需要处理CSS和HTML文件。因为浏览器可以识别这两种文件。
CSS Modules 是采用了另一种方法来代替以前编写HTML的方式。现在我们需要把所有的HTML结构写到一个JS文件当中,比如index.js
。下面我们通过一段代码来预览一下(后面将会有更实际的例子):
import styles from "./styles.css";
element.innerHTML =
`</div></h1><h1 class="${styles.title}">
An example heading
</h1>`;
在我们构建步骤当中,编译器将将会搜索我们所导入的styles.css
文件,然后在我们的JS当中,通过找到styles.title
会把.title
根据之前的styles.css
给解析出来。然后构建工具会同时处理这些东西,把它们生成一个新的HTML和CSS文件,在新的文件当中,我们之前的class名和选择器名将会被一个新的名字所替换掉。
Our generated HTML might look like this:
例如,生成的HTML可能是这样的:
<h1 class="_styles__title_309571057">
An example heading
</h1>
生成的CSS可能是这样的:
._styles__title_309571057 {
background-color: red;
}
之前的class属性和选择器.title
全都被这个新的字符串替换掉了。
Hugo Giraudel在他的Understanding the CSS Modules Methodology一文章当中里说了这样一句总结性的话:
class名和选择器名是由构建工具动态生成的,它们是惟一的。
这就是我们前面说的样式只在当前文件内起作用(生成局部作用域)。它们被区域化成一些特定的模板。假设我们有一个buttons.css
文件,此时我们只在buttons.js
文件当中引入这个css文件,那么假设这个css里的.btn
class名就只会在buttons.js
当中起作用,在其它模板文件当中是找不到的(例如在forms.js
),除非我们在forms.js
当中也引入了buttons.css
文件。
但你可能会问:为什么要这么做呢?为什么要把CSS和HTML搞的混在一起呢?
为什么要使用CSS Modules?
其实使用CSS Modules最大的一个好处就是实现组件化(我们引入的所有样式都用在当前的这个组件上)。
我们可以在一个组件上引入多个样式文件:
import buttons from "./buttons.css";
import padding from "./padding.css";
element.innerHTML = `<div class="${buttons.red} ${padding.large}">`;
这么设计也是为了用来解决原本在CSS当中的全局作用域(其实也可以说是命名冲突)带来的问题的。
有时时候,你可能会花比较多的时间来考虑如何避免全名冲突问题。
有时候,你会在需要的时候在你的CSS文件底部添加一些零碎的样式,然后想着以后再去整理这些样式代码,但后来却越加越多,最终放弃治疗…
有时候,你可能会在几个样式文件当中来回修改,可你也不确定它们各自的功能界限,或者有的文件里的大部分内容是用不到的。
有时候,你可能想试着删除一些样式,但发现不好删,因为总有一些地方会用到这些样式,或者样式之间是有依赖关系的。
上面这些”有时候”会让我们很头疼,这些问题会使我们的项目变的非常臃肿而且很乱。
但使用了CSS Modules后,它的局部作用域的概念就解决了上面所说的这些问题。你只需要写出你要的效果就可以了,不需要考虑其它问题。
例如你现在在项目当中使用了CSS Modules,此时你在CSS当中定义了一个random-gross-class
类,然后在HTML当中引用了这个类,但是它是不起作用的,因为最终的类名会被解析成一个类似于._style_random-gross-class_0038089
这么一串东西。
composes关键字
现在,我们有一个type.css
模块是单独用来设置文字样式的。文件里面的内容为:
.serif-font {
font-family: Georgia, serif;
}
.display {
composes: serif-font;
font-size: 30px;
line-height: 35px;
}
我们现在在模板当中用到上面的样式:
import type from "./type.css";
element.innerHTML =
`<h1 class="${type.display}">
This is a heading
</h1>`;
最终生成的HTML结构将会是这样的:
<h1 class="_type__display_0980340 _type__serif_404840">
Heading title
</h1>
可以看到,两个class样式都被加了上去,因为我们这里使用了composes
关键字,这样就避免会发生像在Sass中使用@extend
带来的问题。
我们甚至可以使用composes
来使用另外一个CSS文件里的class:
.element {
composes: dark-red from "./colors.css";
font-size: 30px;
line-height: 1.2;
}
不需要使用BEM
当我们在使用CSS Modules的时候,是不需要考虑BEM的。
译者:
简单来说,BEM是把样式按功能分成了三类-Block, Element, Modifier。例如:/* Block component */ .btn {} /* Element that depends upon the block */ .btn__price {} /* Modifier that changes the style of the block */ .btn--orange {} .btn--big {}
不需要考虑BEM的原因有两个:
-
易解析-像
type.display
这样的代码会很容易很清晰的被解析成类似于.font-size__serif--large
这种。现在,貌似生成的class名更加BEM化,选择器的名字更长的,更像是我们想要的那种。 -
本地作用域-假设,当前有一个CSS模块(文件)当中有一个
.big
的class,该class的作用是改变font-size
。同时在另外一个CSS模块当中,也有一个.big
,而这个.big
则同时改变了padding
和font-size
。不用担心,它们之间是不冲突的。因为它们都有自己的作用域。即使我们在一个模板当中将这两个CSS模块都引入了也没关系,编译器会最终会给它们取成不同的名字。
是不是很牛B?上面说的只是CSS Modules其中一部分好处而已。
如果你还要了解CSS Modules的其它的一些牛B的地方, Glen Madden的这篇CSS Modules-Welcome to the Future会帮到你。
下面一篇文章当中,我们将介绍如何在项目当中通过Webpack来使用CSS Modules,还将会使用到一些ES2015中的新技术。
:-qq2 :-qq2 :-qq2 最近在听你的网易云课堂的视频,讲的很棒。这个文章赞!!!