Skip to content

模块化CSS

在实际的软件开发过程中,我们的时间和精力不仅花在写新代码上,还要用于持续更新和维护现有代码。
对于CSS来说,这就带来了一堆新问题。

修改现有样式的时候,受影响的页面和元素是不确定的。
有个老笑话是这么说的:两个CSS属性走进了一间酒吧,结果另一间酒吧里的高脚凳摔倒了。
那么问题来了:要怎么确保修改的影响范围和预期一致呢?怎样才能不影响我们不想修改的那些元素?

我们将讨论这些问题。我们会谈到CSS架构,但不会过多涉及具体样式的书写,而是更多地关注CSS选择器和匹配的HTML元素。
如何组织代码结构,决定了后续能否安全地修改代码,而不会有副作用。我们从理解模块化CSS开始。

模块化CSS(Modular CSS)是指把页面分割成不同的组成部分,这些组成部分可以在多种上下文中重复使用,并且互相之间没有依赖关系。
最终目的是,当我们修改其中一部分CSS时,不会对其他部分产生意料之外的影响。

这跟组合家具的原理类似。例如,宜家厨房不是建造一个大型的橱柜单元,而是设计成各种独立的小件,让顾客可以任选购买。这
些小件看上去风格一致,组合起来也会很和谐。这样一来,顾客就可以在布置的时候把这些小件随意摆放到自己喜欢的位置。
模块化CSS也是这样,它不是直接编写一个大型网页,而是编写页面的每个部分,然后按照你需要的效果组合在一起。

在计算机科学中,编写模块化代码并不是什么新潮的做法,但开发人员近几年才开始将其引入CSS。
随着现代网站和Web应用程序体量越来越大、越来越复杂,我们不得不寻找一些方法来管理日益庞大且繁杂的样式表。

之前的样式表可以使用选择器在页面上随意修改,模块化的样式则允许开发人员添加一些限制。
我们把样式表的每个组成部分称为模块(module),每个模块独立负责自己的样式,不会影响其他模块内的样式。
也就是说,在CSS里引入了软件封装的原则。

封装(encapsulation):——相关的函数和数据集合在一起组成对象,通常用来隐藏结构化对象内部的状态或值,从而使外部因素不能操作对象内部。

CSS中没有数据和传统函数的概念,但是有选择器及其命中的页面元素。
为了达到封装的目的,这些会成为模块的组成部分,并且每个模块都只负责少量的DOM元素的样式。

有了封装的思想,我们就可以为页面上那些彼此分立的组件定义模块了,像导航菜单、对话框、进度条、缩略图,等等。
可以通过为DOM元素设置一个独一无二的的类名来识别每个模块。
同时,每个模块包含一系列子元素,构建成页面上的组件。模块内部可以嵌套其他模块,最终构成完整的页面。

基础样式:打好基础

开始写模块化样式之前,需要先配置好环境。每个样式表的开头都要写一些给整个页面使用的通用规则,模块化CSS也不例外。
这些规则通常被称为基础样式,其他的样式是构建在这些基础样式之上的。
基础样式本身并不是模块化的,但它会为后面编写模块化样式打好基础。

新建一个网页和一个样式表,把代码清单9-1中的基础样式粘贴到CSS中。这里只是列举了你可能用到的一些基础样式。

代码清单9-1 添加基础样式

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
:root {
    box-sizing: border-box;
}

*,
*::before,
*::after {
    box-sizing: inherit;
}

body {
    font-family: Helvetica, Arial, sans-serif;
    margin: 0;
}

其他常用的基础样式还包括链接的颜色、标题的样式、外边距等。<body> 标签默认的外边距很小,你可能会考虑将它的外边距去掉。根据项目的实际情况,你也可能想为表单字段、表格和列表等添加一些样式。

提示:
这里推荐一个叫作 normalize.css 的库,这个小样式表可以协助消除不同的客户端浏览器渲染上的不一致。
可以从 https://necolas.github.io/normalize.css/ 下载该库,然后添加到自己的样式表前面作为基础样式的一部分。

基础样式应该是通用的,只添加那些影响页面上大部分或者全部内容的样式。
选择器不应该使用类名或者ID来匹配元素,应只用标签类型或者偶尔用用伪类选择器。
核心思想是这些基础样式提供了一些默认的渲染效果,但是之后可以很方便地根据需要覆盖基础样式。

基础样式配置完成以后,很少会再修改。
我们会在基础样式的稳定表现之上,构建模块化CSS。在样式表中,基础样式后面的内容将主要由各种模块组成。

一个简单的模块