将CSS层叠层整合到现有项目中
本文旨在分享将CSS层叠层整合到现有遗留代码库的完整、未经过滤的实践经验。实际上,这是关于重构现有CSS以使用层叠层而不会破坏任何功能的过程。
理解项目
在开始使用@layers之前,我们需要充分了解正在处理的内容。项目包含三个文件:index.html、index.css和index.js。
index.css文件超过450行代码,初步浏览就能发现一些明显问题:
- 相同选择器指向相同HTML元素的代码重复严重
- 使用了相当多的
#id选择器
#botLogo被定义了两次,相隔70多行
!important关键字在整个代码中被随意使用
规划层结构
我决定将样式分成五个不同的层:
- reset:浏览器默认重置,如box-sizing、边距和内边距
- base:HTML元素的默认样式,包括默认排版和颜色
- layout:控制元素位置的主要页面结构
- components:可重用的UI片段,如按钮、卡片和菜单
- utilities:单一辅助修饰符
在文件顶部定义层顺序:
1
|
@layer reset, base, layout, components, utilities;
|
整合层叠层
重置层
通用选择器(*)样式包含经典的重置样式,非常适合放在@layer reset中:
1
2
3
4
5
6
7
|
@layer reset {
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
}
|
基础层
body选择器包含项目的核心样式,如背景和字体:
1
2
3
4
5
6
7
|
@layer base {
body {
background-image: url("bg.svg");
font-family: "Poppins", sans-serif;
/* ... 其他样式 */
}
}
|
将ID转换为类
我坚信尽可能使用类选择器而不是ID选择器。这默认保持较低的特异性,防止特异性冲突,并使代码更易维护。
我将HTML中id="loader"的元素重构为class="loader",同时修复了一些缺少闭合标签的div元素。
动画
关键帧动画有点棘手,但我最终选择将动画隔离在它们自己的新第五层中:
1
2
3
4
5
6
7
8
9
10
11
12
13
|
@layer reset, base, layout, components, utilities, animations;
@layer animations {
@keyframes loading {
/* ... */
}
@keyframes loading2 {
/* ... */
}
@keyframes pageShow {
/* ... */
}
}
|
布局
.page选择器主要控制内容的初始可见性,属于布局层:
1
2
3
4
5
|
@layer layout {
.page {
display: none;
}
}
|
自定义滚动条
滚动条是跨站点的全局元素,适合放在@layer base中:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
|
@layer base {
::-webkit-scrollbar {
width: 8px;
}
::-webkit-scrollbar-track {
background: #0e0e0f;
}
::-webkit-scrollbar-thumb {
background: #5865f2;
border-radius: 100px;
}
::-webkit-scrollbar-thumb:hover {
background: #202225;
}
}
|
导航
nav元素是定义导航栏位置和尺寸的主要结构容器,属于布局层:
1
2
3
4
5
6
7
8
9
|
@layer layout {
nav {
display: flex;
height: 55px;
width: 100%;
padding: 0 50px;
/* ... */
}
}
|
组件层
各种可重用组件,如加载器、菜单、按钮等,都放在组件层:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
|
@layer components {
.loader {
width: 100%;
height: 100vh;
/* ... */
}
.mainMenu {
display: flex;
flex-wrap: wrap;
list-style: none;
}
.btn {
color: #fff;
background-color: #1d1e21;
font-size: 18px;
/* ... */
}
}
|
媒体查询
媒体查询应该与它们影响的元素放在同一层中,这样可以:
- 将响应式样式与其基本元素样式保持在一起
- 使覆盖可预测
- 与现代Web开发中常见的基于组件的架构很好地配合
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
|
@layer components {
.mainMenu {
display: flex;
flex-wrap: wrap;
list-style: none;
}
@media (max-width: 900px) {
.mainMenu {
width: 100%;
text-align: center;
height: 100vh;
display: none;
}
}
}
|
工具层
工具层保留用于具有特定目的的辅助类:
1
2
3
4
5
6
7
8
9
10
11
|
@layer utilities {
.noselect {
-webkit-touch-callout: none;
-webkit-user-select: none;
-khtml-user-select: none;
-webkit-user-drag: none;
-moz-user-select: none;
-ms-user-select: none;
user-select: none;
}
}
|
挑战与经验
遇到的困难
- 确定起点困难:对于现有项目,很难确定从哪里开始
- 浏览器支持:层叠层目前有94%的支持率,但可能需要支持不支持分层样式的旧版浏览器
- 媒体查询定位:媒体查询在过程中的位置不明确
- !important关键字:它们颠倒了整个分层优先级系统
层叠层的价值
建立层确实改善了代码,真正的胜利在于更可维护的样式集:
- 更容易找到所需内容
- 知道特定样式规则的作用
- 知道在哪里插入新样式
然而,层叠层并不是银弹解决方案。如果HTML结构混乱,那么解构这种混乱的工作量会更高,并且需要同时重写标记。
结论
重构CSS以使用层叠层绝对值得,仅维护增强就足够了。从零开始定义层可能"更容易",因为需要整理的继承开销和技术债务更少。但如果必须从现有代码库开始,可能需要先解构样式的复杂性,以确定需要多少重构工作。
层叠层展示了使用语言提供的工具(而不是使用变通方法或绕开问题的方法)是有回报的。至少,从重置层开始总是很容易的。这些样式总是会被覆盖,因此将它们放在一个层中使一切变得更容易,并且能够编写更复杂的重置,而无需到处使用:where()。