当前内容所在位置(可进入专栏查看其他译好的章节内容)
- 【第九章 CSS 的模块化与作用域】 ✔️
- 9.1 模块的定义
- 9.1.1 模块和全局样式
- 9.1.2 一个简单的 CSS 模块
- 9.1.3 模块的变体
- 9.1.4 多元素模块
- 9.2 将模块组合为更大的结构
- 9.2.1 模块中多个职责的拆分
- 9.2.2 模块的命名
- 9.3 CSS 的作用域
- 9.3.1 CSS 作用域的就近原则
- 9.3.2 划定作用域的边界
- 9.3.3 CSS 中的隐式作用域
- 9.3.4 关于 CSS 作用域与层叠图层
- 9.4 CSS 模式库 ✔️
- 9.5 本章小结 ✔️
文章目录
- 9.4 CSS 中的模式库 Pattern libraries
- 9.4.1 采用 CSS 优先的工作流程 Using a CSS-first workflow
- 9.4.2 重构与重大变更 Refactoring and breaking changes
- 9.5 本章小结 Summary
《CSS in Depth》新版封面
译者按
本篇为第 9 章的最后一节内容,介绍了 CSS 模式库的相关知识。这一节整合了上一版中第 10 章的相关内容,删除了之前关于 KSS 第三方工具库的使用说明,更加聚焦 CSS 本身的组织管理和实际应用。尽管早期的 KSS 在样式的模块化管理方面提供了颇有价值的一站式解决方案,但也存在诸多问题:学习曲线相对陡峭、功能单一(仅关注 CSS 的管理)、未能跟进业内对设计系统的关注、项目打包集成困难、社区支持不足等等。因此第一版的第 10 章只保留了很少内容,但也不失为了解 CSS 从中小型项目过渡到大型项目管理过程中经历的发展轨迹,同时也能从某种意义上理解当下 Ant Design 等设计系统的优势所在。
9.4 CSS 中的模式库 Pattern libraries
开始用模块化的方式编写 CSS 后,Web 页及 Web 应用的构建方式也将随之改变。一开始,这些页面在构建时可能并没有什么特别之处;可一段时间过后,您会发现创建一个新页面所需要的很多模块都已经准备就绪了。比如新建一个媒体对象、或者下拉菜单,亦或是导航菜单,由于之前已经创建过一版了,就积攒了一些现成的样式;最后只需要按照恰当的方式在 HTML 中添加必要的元素标签和样式类即可。
因为模块都是可复用的,所以在编写页面相关板块时就不用再往样式表添加新样式了。与以往先写 HTML 再设计样式的构建模式不同,此时只要利用好这些现成的模块,组装到一起,就可以生成一个新页面。项目进行得越深入,需要的新 CSS 就越少。这时我们需要关注的就不再是新的 CSS 声明,而是样式表里所有可用的模块构成的模块清单了。
将模块清单整合为一组文档,这在大型项目中已经成为通用做法。该文档有时也被称为 模式库(pattern library)。模式库并非网站或应用程序的一部分,而是单独的一组 HTML 页面,用来展示各个 CSS 模块的具体用法,成为您和您的团队后续建站时的必备开发工具。
模式库的具体构建方法很大程度上取决于您熟悉的技术栈,或者项目团队最终确定的技术选型。比如项目是用某个 JavaScript
框架开发的,就可以考虑像 Storybook
(https://storybook.js.org/)这样兼容该框架的构建工具;或者直接手动构建一组 HTML 文档页,并通过索引和具体示例来介绍模块的用法。
9.4.1 采用 CSS 优先的工作流程 Using a CSS-first workflow
在给网站或应用构建新模块时,建议先将其添加到模式库中,然后再应用于页面。这样的开发方案我称之为 CSS 优先(CSS-first)。
与之前先写 HTML 不同,这时得先从 CSS 进行开发。在将样式应用到具体项目前,您可以(并且也应该)按照构建模式库的方式来开发 CSS,具体开发流程如下:
- 开发页面时,最好先有一个草图(sketch)或者原型图(mockup),或者其他可以描述页面效果的大致想法。
- 看看模式库。找找现有模块,如果满足页面需求就直接套用。然后从页面的外围(主页面布局和容器)开始,按自己熟悉的方式逐步深入。如果现有模块足以构建整个页面,就无需添加新的 CSS 了。
- 偶尔也会遇到模式库无法提供的一些功能。这在项目开发早期很常见,后面就会好很多。此时就要根据情况开发一个或多个新模块,或者现有模块的新变体形式;暂停正在开发的页面,在模式库构建出该模块,并为其书写文档,确保其外观与行为模式符合预期。
- 最后回到页面开发,使用刚改好的样式表,并将新模块添加到页面中。
这种开发方式有几个好处。首先,这样写可以为网站提供一致性更好的界面。模式库鼓励开发者复用已有样式,而非重复开发。比如,项目中不应该为 10 个不同的页面分别编写 10 套不同的列表样式,而是更倾向于复用仅有的几种列表类型。CSS 优先的开发方式会强迫开发者停下来思考:是否需要新的样式、现有模块是否可以满足需求。
其次,在按照模式库的方式开始模块时,您可以孤立地看待问题;可以从某个具体的 Web 页面抽离出来,并专注于构建样式模块这样的单一任务上。不同于解决某个页面的某个具体问题,思考新模块的潜在应用场景会相对容易一些,并由此创建出一套通用性更好、可复用性更强的解决方案。
再次,CSS 优先的方式还能让团队中的部分成员专注于 CSS 开发。对 CSS 不太熟悉的开发者可以将部分工作移交给经验更丰富的成员。擅长 CSS 的开发者每完成一个模块,就可以向其他团队成员发送一个链接,指向模式库中的该模块。
最后,CSS 优先的开发方式还可以确保文档是最新的。模式库中的页面是您变更 CSS 样式的测试环境。换句话讲,这些页面会一直呈现出最新的正确行为。修改 CSS 时,使用文档恰好就在一旁的注释块中,这样就可以轻松实现文档的实时更新了。
经常有开发者提问:HTML 究竟该怎样编写才能让样式写起来更轻松。我认为这种提法本身就有问题。相反,我们应该关注的是怎样编写样式,使其可以更好地在任意页面间复用。我们应该先写好 CSS,这样结构良好的 HTML 就是水到渠成的事了。而将 CSS 组织为模块就是一个行之有效的手段。一个 CSS 模块决定了其所需的 HTML 结构,使得该样式能在页面上正常展示。
9.4.2 重构与重大变更 Refactoring and breaking changes
有时也会在修改模块时无需考虑向下兼容的情况。这么做无可厚非,虽然多了一些活,但好歹是可行的。可能您会先完成样式变更,然后遍历整个网站或应用,把每个 HTML 实例都更新一下,让它们符合新的写法。
但我发现最好的做法往往是直接弃用该模块(需要在文档中指明),然后创建一个全新的模块来实现所需的新功能。这样一来,旧模块就可以在原有页面继续生效,而新页面的开发则可以往新模块迁移,因为新模块支持全部功能。
为此,可以使用一个包含三位数字的 语义版本(semver) 来为 CSS 设置版本号。一旦版本号变了,开发者自然就知道模块内容改变了。
语义版本的定义
语义版本(Semver) —— Semantic Versioning 的简写,是一种软件包版本的命名格式。它由三个数字组成,各数字间使用圆点分隔(例如
1.4.2
)。三个数字分别代表主版本号(major version)、次版本号(minor version)和修订版本号(patch version)。了解更多信息,详见语义版本官网 https://semver.org/。
如果只涉及一些小修改,比如 Bug 修复,则增加修订版本号即可(例如,由 1.4.2
改为 1.4.3
);如果添加了新的模块或功能但对现有 HTML 不构成破坏,或者将某个模块标记为已废弃(deprecated)时,则增加次版本号,同时将修订版本号置零(例如,由 1.4.2
改为 1.5.0
);再有,在极少数情况下,我会过一遍样式表并将标记为已废弃的模块全部删掉,这时就该升级主版本号(例如,由 1.4.2
改为 2.0.0
)。而当出现重大设计变更时(例如网站重新设计了),即便现有 API 接口 1 保持不变,也需要升级主版本号。
实际上,版本管理可以采用多种方式,具体取决于使用这些样式的项目实际情况。如果要在 Node.js
模块或者 Ruby Gem
中引入 CSS,那就得用相应的系统构建的版本;如果要在服务器上提供 CSS 静态访问,则可以在 URL 中包含版本号(如 http://example.com/css/1.4.2/styles.css
),并同时支持多个版本。
利用这种方式,就可以按照需求配置项目并使用任意版本的 CSS 了。您可以发布一个包含重大更新的 3.0.0
版本,而 Web 应用则可以继续沿用旧版本,直到开发者彻底更新一遍 HTML 并升级所有已废弃的模块。只要不是刻意升级到新版样式表,改动个别 CSS 并不会破坏现有应用的正常显示。
模式库文档列出了样式表的使用方法,但 HTML 具体启用哪个样式表、采用哪个版本的样式则是开发者说了算。由于 HTML 和 CSS 实现了解耦(decoupled),CSS 可以写好了再应用到 HTML;而在升级新样式表时,HTML 也是完全可控的。这就是 CSS 优先开发的优势所在。
修改模式库时,最好不要一意孤行,先和团队里的其他开发者沟通一下,再决定是否弃用或删除某个模块。必要时可以通过收集他人的反馈来综合判断哪些模块是有用的,哪些已经不再需要了。
通常来讲,CSS 是一门“只增不减”(“additive-only”)的语言。开发者害怕去编辑或删除那些已有的样式,因为他们无法预判这些修改会造成什么样的后果。于是不得不编写新的 CSS 代码,然后添加到样式表底部,或者通过不断提升选择器优先级来覆盖现有样式规则,最终让样式表沦为一堆乱麻而难以维护。
而通过模块化的方式组织 CSS 代码,就可以避免陷入这样尴尬的境地。您会清晰地知道某个模块样式位于何处,每个模块都分工明确,只实现某一个功能。同时,模式库还有助于开发者密切关注样式表开发过程中的一举一动。
9.5 本章小结 Summary
- 模块时一段可复用的小型样式片段,不依赖于页面上下文。模块样式应该集中写到样式表的某个位置,并按照代码封装的相关原则进行组织。模块化 CSS 绝不能进入另一个模块,以期修改其外观。
- 变体类(Variant classes)提供了同一模块样式的不同版本。
- 大型页面构造应该拆分成多个小型模块,并通过组装多个模块来构建出页面。
- 双连字符以及双下划线的命名约定能让模块的结构一目了然。
@scope
规则是 CSS 全新推出的一项功能,可以让一组样式在页面的指定作用域内生效。它是将模块化样式限定在目标模块内的理想工具。通过划定内部作用域边界还可以防止该作用域内的样式声明对边界内部的作用域生效。使用时需要留意该特性最新的浏览器支持情况。- 在大型项目中,可以考虑构建一个模块库来记录和清点项目所使用的模块,并将其作为组装新页面时现有样式模块的参考文档。
关于《CSS in Depth》(中译本书名《深入解析 CSS》)
第 1 版 | 第 2 版 | |
---|---|---|
读者评分 | 原版:4.7(亚马逊);中文版:9.3(豆瓣) | 原版:5.0(亚马逊);中文版:暂无,待出版 |
出版时间 | 原版:2018 年 3 月;中文版:2020 年 4 月 | 原版:2024 年 7 月;中文版:暂无,待出版 |
原价 | 原版:$44.99;中文版:¥139.00 | 原版:$59.99;中文版:暂无,待出版 |
现价 | 原版:$36.49;中文版:¥52.54 起步 | 原版:$52.09;中文版:暂无,待出版 |
原版国内预订 | 起步价 ¥461.00 | 起步价 ¥750.00 |
本专栏为该书第 2 版高分译文专栏,全网首发,精译精校,持续更新,计划今年内完成全书翻译,敬请期待!!!
目前已完结的章节(可进入本专栏查看详情,连载期间完全免费):
- 第一章 层叠、优先级与继承(已完结)
- 1.1 层叠
- 1.2 继承
- 1.3 特殊值
- 1.4 简写属性
- 1.5 CSS 渐进式增强技术
- 1.6 本章小结
- 第二章 相对单位(已完结)
- 2.1 相对单位的威力
- 2.2 em 与 rem
- 2.3 告别像素思维
- 2.4 视口的相对单位
- 2.5 无单位的数值与行高
- 2.6 自定义属性
- 2.7 本章小结
- 第三章 文档流与盒模型(已完结)
- 3.1 常规文档流
- 3.2 盒模型
- 3.3 元素的高度
- 3.4 负的外边距
- 3.5 外边距折叠
- 3.6 容器内的元素间距问题
- 3.7 本章小结
- 第四章 Flexbox 布局(已完结)
- 4.1 Flexbox 布局原理
- 4.2 弹性子元素的大小
- 4.3 弹性布局的方向
- 4.4 对齐、间距等细节处
- 4.5 本章小结
- 第五章 网格布局(已完结)
- 5.1 构建基础网格
- 5.2 网格结构剖析 (上)
- 5.2.1 网格线的编号(下)
- 5.2.2 网格与 Flexbox 配合(下)
- 5.3 两种替代语法
- 5.3.1 命名网格线
- 5.3.2 命名网格区域
- 5.4 显式网格与隐式网格(上)
- 5.4.1 添加变化 (中)
- 5.4.2 让网格元素填满网格轨道(下)
- 5.5 子网格(全新增补内容)
- 5.6 对齐相关的属性
- 5.7 本章小结
- 第六章 定位与堆叠上下文(已完结)
- 6.1 固定定位
- 6.1.1 创建一个固定定位的模态对话框
- 6.1.2 在模态对话框打开时防止屏幕滚动
- 6.1.3 控制定位元素的大小
- 6.2 绝对定位
- 6.2.1 关闭按钮的绝对定位
- 6.2.2 伪元素的定位问题
- 6.3 相对定位
- 6.3.1 创建下拉菜单(上)
- 6.3.2 创建 CSS 三角形(下)
- 6.4 堆叠上下文与 z-index
- 6.4.1 理解渲染过程与堆叠顺序(上)
- 6.4.2 用 z-index 控制堆叠顺序(上)
- 6.4.3 深入理解堆叠上下文(下)
- 6.5 粘性定位
- 6.6 本章小结
- 第七章 响应式设计(已完结)
- 7.1 移动端优先设计原则(上篇)
- 7.1.1 创建移动端菜单(下篇)
- 7.1.2 给视口添加 meta 标签(下篇)
- 7.2 媒体查询(上篇)
- 7.2.1 深入理解媒体查询的类型(上篇)
- 7.2.2 页面断点的添加(中篇)
- 7.2.3 响应式列的添加(下篇)
- 7.3 流式布局
- 7.4 响应式图片
- 7.5 本章小结
- 第八章 层叠图层及其嵌套
- 8.1 用 layer 图层来操控层叠规则(上篇)
- 8.1.1 图层的定义(上篇)
- 8.1.2 图层的顺序与优先级(下篇)
- 8.1.3 revert-layer 关键字(下篇)
- 8.2 层叠图层的推荐组织方案
- 8.3 伪类 :is() 和 :where() 的用法
- 8.4 CSS 嵌套的使用
- 8.4.1 嵌套选择器的使用
- 8.4.2 深入理解嵌套选择器
- 8.4.3 媒体查询及其他 @规则 的嵌套
- 8.5 本章小结
作者在这里使用了 API 接口的说法,因为他认为模式库的启用在某种意义上相当于维护了一组与 CSS 进行交互的 API 接口。新版中删掉了上一版的相关解释,这里补充说明。 ↩︎