CSS重构笔记

Author Avatar
KING Apr 20, 2018 Apr 20, 2018 UPDATED

什么是重构

重构是指在不改变代码行为的前提下,重写代码,使其更加简洁、易于复用。与软件架构之间有什么关系呢?

什么是软件架构

术语软件架构用来描述软件项目的各个不同部件之间的组合方式。就像生物一样,软件系统通常由很多较小的部件组成,每个部件擅长做一件事。将这些部件组合起来,一起工作,可形成更大的软件系统。

优秀架构是可预测的

软件架构可预测是指可以对软件的工作方式和结构做出准确的假设。可预测性表明预先的规划是合理的,并有助于节省开发时间,可以避免下列问题:

  • 组件的功能是什么
  • 某一段代码在何处
  • 新代码加到何处

在可预测的架构中,人们可以做出精确的假设,不熟悉代码的开发人员也能够更快地理解该架构。-

优秀架构可提升代码复用性

代码复用优势明显,不用重写已有代码,可以加快开发速度。同理,解决某一问题所需的代码越少,维护所有用该代码实现的功能所需的时间就越少。

例如,在一段代码中发现了一处 bug,而由于项目多处用到该代码,故将 bug 带到了多处。你只需在一个位置修复该 bug,就可以相应修复其他各处的 bug。

优秀架构可扩展

可扩展性是优秀架构所遵循的一项原则,在具备该特点的系统上增加新功能很容易。大多数软件无法在一天之内开发完成,因此软件架构适于增量开发,且不需要做大的结构性变化,这一点非常重要。

优秀架构可维护

可维护性软件是指你修改一处代码时,没必要大规模改动其他代码。跟可扩展性非常类似,可维护性对于架构也很重要。对于可维护的优秀架构,修改其现有功能很容易。

软件架构和重构

概括来讲,重构有助于维护和提升软件架构。重构就是指调整代码结构、使其更具意义的一套技术。重构可使代码可预测、可复用、可扩展和可维护。

需要重构的原因

需求变更

软件系统随着需求的变动而进化。软件在编写时是为了满足一组需求,可能没有考虑另一组需求,因此,需求变更时,代码也必须随之改变。此外,如果软件开发还有时间要求,有时会为优先满足功能的实现而走“捷径”,进而可能会影响代码质量。

架构设计不合理

投入大量时间事先规划好一切并不总是可行的。开发之初,若不知道各组件的组合方式,开发过程也许需要重构。非常常见的做法是,快速开发一个新功能(可能会为实现功能而走“捷径”),以验证它对用户是否有吸引力。如确实能够吸引用户,再将代码整理干净;如达不到预期效果,则删除代码。

低估困难

预估软件开发需要多长时间很难,但不幸的是,常常根据估计结果来安排开发计划。如果项目开发周期被低估,将迫使开发人员“为了完成而完成”,而不会花很多时间思考。

忽视最佳实践

跟上每一种最佳实践的发展步伐很难,技术发展日新月异,因此之前的最佳实践也许优势不再。

什么情况下应该重构代码

结合代码的上下文重构代码会更加容易。因此,如果你修复的 bug 或开发的新功能用到了已有代码,处理小任务时顺便重构代码,重构是最好的选择。不断坚持重构代码,代码质量将达到卓越,前提是改动符合优秀架构的特点。

然而,有时你会遇到一段有很多依赖的代码,也许需要决定是否对其重构。对于具有很多依赖的代码,你改动得越多,需要更新的依赖就越多。

什么情况下不应该重构代码

知道什么情况下不应该重构,甚至比知道什么情况下应该重构更为重要。仅当重构能够改善架构或使代码符合编码规范时,才应进行重构。

重构示例

重构 CSS 时,确保重写代码没有改变展示效果同样重要。但无法直接测试,因为重构 CSS 带来的是视觉上的变化,而不是明确的数值上的变化。

简单的说,方式如下:
将样式抽取出来作为单独的文件,可提升代码的复用性,因为抽取出来的样式可用于多个文件。将 CSS 置于一个独立于 HTML 代码的文件后,HTML 和 CSS 都更加清晰易读,因为 HTML 中不会包含冗长的样式定义,并且 CSS 可以按照符合逻辑的方式以声明块的形式组织在一起。最后,测试重构是否改变了页面;可手动用浏览器重新加载页面,与重构前的截图进行对比。

编写更优质的 CSS

高性能选择器

简单的选择器比起复杂的选择器性能更高;应该优先选用简单的选择器,这是因为简单的选择器复用程度高,易于理解,同时需要对选择器性能有个整体认识。

从右向左匹配选择器

Web 浏览器需要快速选择并为元素应用样式,以便尽快为用户提供可用的网页。浏览器从右向左匹配选择器,因此它能够忽略前面不匹配的元素,而不必把时间浪费到确认元素是否匹配上。

如下是一段层级结构简单的 HTML 代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
<html>
<head>
<title>Another Example</title>
</head>
<body>
<div>
<nav>
<ul>
<li>
<strong>Not a Link</strong>
</li>
</ul>
</nav>
</div>
<div>
<nav>
<ul>
<li>
<a href="#" class="nav-link">Link</a>
</li>
</ul>
</nav>
</div>
</body>
</html>

如果用 div > nav > ul >li > a 选择锚点标签,并且浏览器尝试从左向右匹配元素,它需要执行下列步骤。

  1. 遍历每个元素,检查它是否是 <div> 元素。
  2. 检查步骤 1 匹配到的每个 <div> 元素,确认它是否有子节点 <nav>
  3. 检查步骤 2 匹配到的每个 <nav> 元素,确认它是否有子节点 <ul>
  4. 检查步骤 3 匹配到的每个 <ul> 元素,确认它是否有子节点 <li>
  5. 检查步骤 4 匹配到的每个 <li> 元素,确认它是否有子节点 <a>
  6. 为找到的那一个 <a> 元素应用样式。

反过来讲,如果同一选择器(div > nav > ul > li > a)从右向左匹配,浏览器需要执行下列步骤。

  1. 遍历每个元素,检查它是否是 <a> 元素。
  2. 检查步骤 1 匹配到的每个 <a> 元素,确认它是否有一个 <li> 父节点。
  3. 检查步骤 2 匹配到的每个 <li> 元素,确认它是否有一个 <ul> 父节点。
  4. 检查步骤 3 匹配到的每个 <ul> 元素,确认它是否有一个 <nav> 父节点。
  5. 检查步骤 4 匹配到的每个 <nav> 元素,确认它是否有一个 <div> 父节点。
  6. 为与选择器相匹配的 <a> 元素应用样式。

虽然这两种顺序步骤数相同,但存在较大的区别:从左向右匹配时,两个 <div> 元素都需要匹配一遍。而从右向左匹配时,浏览器能够直接排除不包含锚点标签的整个 <div>。若要进一步提升性能,还可以用 .nav-link 类选择锚点标签,那么浏览器只需要遍历每个元素,检查它是否包含该类。

关键选择器

浏览器从右向左匹配元素,因此它能够及时排除与选择器不匹配的元素。选择器最右边的部分叫作关键选择器。

分析一个更加极端的例子,以 body 为祖先元素的通用选择器。

1
2
3
body * {
font-size: 12px;
}

选择的是祖先元素为 <body> 标签的任意元素。从右向左解析该选择器,能够选择页面的每个元素,并向上回溯查看它是否有个 <body> 祖先元素。该选择器效率极低,因为几乎每个可见元素都是 <body> 元素的后代。

单独使用通用选择器为所有元素(* {} )应用样式,浏览器可以很快完成渲染工作,因为它只需要匹配页面的每个元素。然而,当通用选择器与另一个选择器和结合符配合使用时,浏览器匹配合适的元素所做的工作要更多。只使用通用选择器,不要将其与结合符和其他选择器配合使用可以解决该问题。

分离CSS和JavaScript

由于 JavaScript 和 CSS 两者都依赖于 HTML 元素的类和 ID,因此它们可能会混杂在一起。此外,因为 JavaScript 能够修改 HTML 元素的样式,所以这两种语言的职责可能会变得很混乱。为了区分 CSS 和 JavaScript 的职能,JavaScript 中用来选择元素的类和 ID,不应该再用来为元素添加样式。类似地,用 JavaScript 修改元素样式时,应该通过增加和删除类来实现。

在JavaScript中使用带前缀的类和ID

HTML 中的类既用来为元素添加 CSS 样式,又在 JavaScript 用作选择器,这种情况很常见。同样很常见的是,添加到元素中的类和 ID 只用于选择元素,而不是为元素添加样式。HTML 中的类和 ID,若未在 CSS 中使用,这将使得我们难以找到能够修改元素样式的 CSS。类似地,如果为了让类名更切合它所作用的元素而修改了类名,却没有同步修改 JavaScript 中的类名,JavaScript 代码将不起作用。

比较简单的修改方法是,在只用于 JavaScript 的类和 ID 前添加 js-。例如,如果我们要在 JavaScript 中选择与政策相关的一组选项卡,那么可以用 js-tab-group-policies 作为 ID。只用添加了 js- 前缀的类和 ID 作为 JavaScript 选择器,就可以消除 JavaScript 和 CSS 之间的依赖关系。

在 JavaScript 中,选择元素的最快方式是 ID。

用类修改元素样式

元素样式可以用 JavaScript 修改,很多库(像 jQuery)简化了具体的实现方法。然而,用 JavaScript 修改样式通常表示用 style 属性为元素增加行内样式,这将使得行内样式最精确。此外,在 JavaScript 中修改样式,表示 JavaScript 要为特定的 CSS 样式负责,这超出了它的职责范围。如遇到元素样式需要改动的情况,则不仅要在 CSS 文件中查找现有样式,还要在 JavaScript 文件中查找。

因此,若要修改 HTML 元素样式,不要用 JavaScript 添加 style 属性,而是应该为元素增加或删除类。这样不仅可以应用合适的样式,该元素的 CSS 样式集也能跟其余的网站 CSS 合理地组织在一起。

从实际应用来看,大多数情况下,类和 ID 在 CSS 性能方面没有明显的差别。

类名要有意义

有意义的类名通过描述为什么元素增加样式,从而提供恰如其分的背景信息。这样既可以防止因细节过少而表意模糊,又可以避免因信息过多而妨碍代码重用。

避免使用过于模块化的类
有意义的类名,描述的是应用样式的元素,而不是为元素应用的样式。过于模块化的类

1
2
3
<h1 class="font-bold uppercase blue-text margin-bottom-large no-padding">
Too Many CSS Classes
</h1>

这些类描述的是怎样为元素增加样式,而不是为什么元素增加样式。此外,这些类存在过于模块化问题——因为每个类应用一种样式,它们总是需要一起使用。应该避免使用过于模块化的类,因为它们并不比行内样式更好

1
2
3
4
<h2 style="font-weight: bold; text-transform: uppercase; color: #1200FF;
margin-bottom: 20px; padding: 0">
Too Many CSS Classes
</h2>

这些样式应该放到一起,使用表意明确、能够描述为什么元素增加样式的类名,重构之后,HTML 可读性更强,因为它使用了非常简洁的类名。

1
2
3
<h2 class="section-title">
Too Many CSS Classes
</h2>

1
2
3
4
5
6
7
.section-title {
color: #1200FF;
font-weight: bold;
margin-bottom: 20px;
padding: 0;
text-transform: uppercase;
}

content-box或border-box

因为盒子尺寸有两种不同的计算方法,所以应该考虑其使用场景。content-box 和 border-box 两者没有优劣之分,但是很多人发现 border-box 更直观,因为它描述的是包括边框在内的元素的高度和宽度,而不只是内容区域的尺寸。

任何元素都可以设置 box-sizing 属性,因此可以混用这两种盒子,但是为了保持一致性,通常选用其中一种并坚持使用。具体设置方法是,用通用选择器进行设置,指定盒子的类型:

1
2
3
4
5
*,
*:after,
*:before {
box-sizing: border-box;
}

为样式分类

代码复用是优秀架构的一项基本原则,可以说它是编写高质量 CSS 代码所要重点考虑的原则之一。按照样式的功能对其进行分类和使用,代码的复用方式就会变得更加明显。按用途定义样式,有助于创建更优秀的架构,因为将样式组织成为不同的类别,促使代码可预测性更强、更易于复用。

通用样式

浏览器自带的默认样式表叫作浏览器默认样式,它可为 HTML 元素应用默认的样式。因为不同厂商开发的浏览器不同,所以其默认样式表的某些属性和属性值可能有所差异。

通用样式是指为各种元素的属性设置默认值的样式,否则不同的浏览器将为其应用不同的样式。

测试和记录浏览器默认设置的属性和属性值很难,最通用的样式表是normalize.css,开源通用样式表中的很多样式,它们的最大用途体现在解决传统浏览器的兼容问题方面,其中包含大量用不到的元素的样式,比如 <kbd> 如果不打算使用这些元素,应该考虑将其删除。

基础样式

基础样式旨在为设置更加细致的样式提供基础。基础样式很容易识别,因为它们用单类型选择器,或结合使用非常简单的类型选择器和结合符(例如,用 ul ul 在无序列表中选择无序列表),或使用任何伪类为 HTML 元素添加样式。跟通用样式一样,基础样式是最不精确的样式,

一旦为 HTML 元素设置基础样式后,应该不需要重新声明,除非设置的基础样式不适合目标场景。编写基础样式所要遵循的基本原则是:为元素应用基础样式之外的其他样式时,不需要重写大量基础样式就能实现设计目标。

基础样式应该只为最笼统的使用场景设置属性和属性值。通常为元素设置以下基础属性,它们都继承自祖先元素(除了 margin 和 padding):

  • color
  • font-family
  • font-size
  • font-weight
  • letter-spacing
  • line-height
  • margin
  • padding

记录元数据的标签包括 <head>、<title>、<base>、<link> 和 <meta>。因为不可见,故不为其添加样式。

将定义尺寸的任务交给结构化容器

可复用组件是指添加了样式的元素或元素组合。可复用组件的例子包括按钮、下拉菜单、模态窗口、进度条和选项卡。

创建可复用组件的过程可以简化如下。

  1. 创建组件之前,定义需要实现的行为。
  2. 保持组件样式的粒度,设置合理的默认值。
  3. 若需要重写组件组的可见样式,用容器元素将它们包起来,为该容器定义一个具有区别度的类。
  4. 将定义元素尺寸的任务交给结构化容器。

例如要创建选项卡组件。需求如下:

  • 选项卡组件一般有三个选项卡,但是该种组件应该能够支持两个及以上选项卡。
  • 选项卡激活时,该选项卡的底边框变为蓝色,背景变为白色。
  • 选项卡处于非激活状态时,背景为灰色。
1
2
3
4
5
6
7
<nav>
<ul class="tab-group">
<li class="tab active"><a href="#">Tab One</a></li>
<li class="tab"><a href="#">Tab Two</a></li>
<li class="tab"><a href="#">Tab Three</a></li>
</ul>
</nav>

保持组件样式的粒度是指为组件的每个元素添加样式,以便它们能够复用。将选项卡的样式抽象为一个可复用的类,定义了.active 类,可以根据选项卡状态添加它,以表示哪个选项卡处于激活状态。

如要为选项卡应用不同样式,可将定义选项卡样式的任务交由父容器完成。例如实现了一个水平选项卡组件后,还可以实现垂直展示选项卡。

创建一个新的 .tab-group-vertical 类,该类包含 .tab 元素,然后用 .tab-group 类将 .tab 元素组合在一起:

1
2
3
4
5
6
.tab-group,
.tab-group-vertical {
list-style: none;
margin: 0;
padding-left: 0;
}

.tab 类将只包含适用于所有选项卡的样式:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
.tab {
background-color: #F2F2F2;
margin-left: 0;
margin-right: 0;
position: relative;
}

.tab:hover {
background-color: #F9F9F9;
}

.tab.active {
background-color: #FFFFFF;
color: #000000;
}

将 border、border-radius 和 display 样式交由合适的父容器,.tab-group、.tab-group-vertical 类各有各的边框样式:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
/**
* 选项卡组件样式
*/

.tab {
background-color: #F2F2F2;
margin-left: 0;
margin-right: 0;
position: relative;
}

.tab:hover {
background-color: #F9F9F9;
}

.tab.active {
background-color: #FFFFFF;
color: #000000;
}

.tab > a {
color: inherit;
display: block;
height: 100%;
padding: 12px;
text-decoration: none;
width: 100%;
}

/**
* 选项卡组件容器
*/

.tab-group,
.tab-group-vertical {
list-style: none;
margin: 0;
padding-left: 0;
}

.tab,
.tab-group,
.tab-group-vertical {
border-color: #EEEEEE;
border-style: solid;
border-width: 0;
}

/**
* 水平选项卡组
*/

.tab-group {
border-bottom-width: 1px;
}

.tab-group .tab {
border-bottom-width: 1px;
border-top-width: 1px;
bottom: -1px;
display: inline-block;
}

.tab-group .tab:first-child {
border-left-width: 1px;
border-top-left-radius: 4px;
}

.tab-group .tab:last-child {
border-right-width: 1px;
border-top-right-radius: 4px;
}

.tab-group .tab.active {
border-bottom-color: #2196F3;
border-bottom-width: 1px;
}

/**
* 垂直选项卡组
*/

.tab-group-vertical {
border-left-width: 1px;
}

.tab-group-vertical .tab {
border-left-width: 1px;
border-right-width: 1px;
left: -1px;
display: block;
}

.tab-group-vertical .tab:first-child {
border-top-width: 1px;
border-top-right-radius: 4px;
}

.tab-group-vertical .tab:last-child {
border-bottom-width: 1px;
border-bottom-right-radius: 4px;
}

.tab-group-vertical .tab.active {
border-left-color: #2196F3;
border-left-width: 1px;
}

组件能够复用固然很好,但是很难预测它出现在页面中的位置。这也正是为什么要将设置元素尺寸的任务交给盛放组件的元素。
比如如下html结构:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
<nav class="global-nav">
<ul class="tab-group-vertical">
<li class="tab"><a href="#">Home</a>
<li class="tab active"><a href="#">Policies &amp; Fees</a>
<li class="tab"><a href="#">Documents</a>
<li class="tab"><a href="#">Billing</a>
</ul>
</nav>
<main class="content">
<nav class="tabbed-pane">
<ul class="tab-group">
<li class="tab active"><a href="#">Policy One</a>
<li class="tab"><a href="#">Policy Two</a>
<li class="tab"><a href="#">Policy Three</a>
</ul>
<ul class="tab-group">
<li class="tab active"><a href="#">Fee One</a>
<li class="tab"><a href="#">Fee Two</a>
<li class="tab"><a href="#">Fee Three</a>
</ul>
</nav>
</main>

结构化样式

结构化样式包括组件及其容器,比如 .tabbed-pane 元素。既然需要为布局定义尺寸,可以用结构化样式设置尺寸,然后将其添加给组件和容器。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
/**
* 选项卡组件容器
*/

.tabbed-pane {
display: block;
width: 100%;
}

.tabbed-pane .tab-group {
float: left;
width: 45%;
}

.tabbed-pane .tab-group:first-child {
margin-right: 5%;
}

.tabbed-pane .tab-group:last-child {
margin-left: 5%;
}

/**
* 结构化样式
*/

.global-nav {
float: left;
padding: 5% 0;
width: 10%
}

.content {
float: left;
padding: 5%;
width: 80%;
}

功能样式

功能样式是指开发人员在定义 HTML 元素的类时为其指定的样式,或满足特定条件时,用 JavaScript 添加的样式。例如,如果按下按钮隐藏某个元素,可以通过添加下面这个类来实现:

1
2
3
.hidden {
display: none !important;
}

添加 !important 能够确保不管为元素增加或删除其他的类,元素将一直处于隐藏状态。

浏览器特定样式

由于老的浏览器有一些怪癖,可以使用Hack,以克服这些问题。例如,如果需要用支持老 IE 浏览器,那么应该将其放到单独的样式表中,并用条件注释(conditional comments)添加对该样式表的引用,只为特定版本的浏览器加载这些样式。

1
2
3
<!–-[if IE 7]>
<link rel="stylesheet" href="ie7.css" type="text/css" />
<![endif]–->

媒体查询要靠近相关声明块
媒体查询用于根据条件为元素应用不同的样式,比如根据浏览器视口的宽度变化调整样式。应该将媒体查询写到它们所作用的声明块附近,而不是将其置于 CSS 文件的末尾或单独的文件中,因为这样做可以为样式是如何起作用的提供更多背景信息。

代码的组织和重构策略

重构前审查 CSS

从以下更高的角度来审查 CSS,将非常有助于重构:

  • 所用到的属性列表
  • 使用某一特定属性的声明块列表
  • 使用的颜色数量
  • 使用的最高和最低权重
  • 拥有最高和最低权重的选择器
  • 选择器的长度
    CSS Dig 是Chrome的一款插件,可以用它获取到以上信息。能够帮助调整好 CSS 代码。

重构策略

要注意,条件允许的话,应该只对能够维护的小块代码进行重构,并做到经常评审和发布。如果一次重构和发布大量代码,引入错误的风险更大,因为改动的内容更多。重构大量代码还会延缓新功能的上线,如果处理不当,在源文件版本控制系统合并代码也将更加复杂,甚至将引入错误。如果对小块代码进行重构,可能引发错误问题的改动将会更少,代码测试更加容易。

保持规则结构的一致性
比如确定好声明块的格式和声明语句的顺序。

删除僵尸代码
CSS 代码库不能留有僵尸代码,比如没有使用的声明块、重复的声明块和声明语句。

分离 CSS 和 JavaScript
为元素添加样式的类和 ID 不应该在 JavaScript 中用作选择器,CSS 和 JavaScript 应该尽早分离,因为类和 ID 很可能会调整,这可能会破坏 JavaScript 代码。

分离基础样式
任何网站的基础样式都应该尽可能的简单,因为它们使用的是类型选择器。

将基础样式分为以下不同类别:

  • 标题(

  • 文本(例如:

  • 超链接(
  • 列表(
  • 表单(例如:
  • 表格(例如:、、、、 和
  • 媒体(例如:

分完类之后,可以用 CSS Dig 寻找某一特定类别的选择器。找到选择器的使用频率和使用位置之后,可以对它们进行比较,看看哪个属性更常用。如果一个类型选择器单独使用,且只用过一次,就可以放心将其删除。

如果一个类型选择器用过多次,按以下步骤重构。

  1. 对于样式要予以重构的类型选择器,在基础样式中新建一条规则。
  2. 从所有用到该类型选择器的地方找到最常用的属性,将其添加到新规则中。
  3. 从其他规则删除重复的属性,因为它们可以继承新定义的基础样式。

删除冗余的 ID
CSS 文件中权重最高的选择器使用 ID。因为同一个 ID 在一个网页最多只能使用一次,一个选择器包含多个 ID 实属冗余。

将 ID 转化为类
删除冗余 ID 之后,剩余的 ID 可以转化为类。最终得到的 CSS 权重更低、更易于复用。将 ID 改为类时,请记得使用意义明确的类名,切记不要使用晦涩或过于精确的名称。

区分功能性样式
功能性样式是唯一应该使用 !important 声明的样式。若不得不使用 !important 的样式,且用途单一(如隐藏元素),应将其作为功能样式写到样式表的同一地方。

定义可复用组件
定义可复用组件有助于删除重复的 CSS。删除多余的 ID 后,通常余下的那个 ID 用于为元素添加样式。可以用作可复用组件的界面。

可以从经常重复使用的界面(例如:选项卡)着手,花点时间调研网站什么地方用到了类似的界面。记录该界面的各种变体,并判断它们是合理的,还是由于不一致的 CSS 而导致的。

使用相同的组件样式可以防止出现代码重复问题,但是若要重新定义组件的样式,则要把样式添加到容器组上或使用结构化样式。

删除行内 CSS 和过于模块化的类
删除行内 CSS 和过于模块化的类应该同时进行,因为它们在本质上是相同的,只不过用 style 属性添加的行内 CSS 其特指度更高,除非用 !important 声明覆盖了行内样式。

隔离面向特定浏览器的 CSS 样式
浏览器之间存在差异,因此为了实现兼容,会在 CSS 中使用一些特定的“Hack”,而这些代码很容易污染其他 CSS,因此需要对其进行区分。但是在隔离之前,需判断是否能够放弃支持这些浏览器。如果无法放弃对一款浏览器的支持,那么使用条件注释专门针对该浏览器为某一元素添加样式即可。

评估重构是否成功

判断代码重构之后成功与否的最主要且最明显的方式是确认网站的行为是否倒退。重构是指在不改变代码行为的前提下,重写代码使其更加简洁。

若没问题,接下来需要考虑其他方面:

  • 低耦合度
    高质量的 CSS 是指 CSS 与使用它的 HTML 结构分离开来。通过创建可复用组件和用容器包裹组件,可以实现 CSS 和 HTML 的分离。虽然一定程度的耦合度一直存在,但是还是要避免使用过于复杂的选择器。CSS Dig 这类工具能够嗅探出复杂和过于精确的选择器。审计网站并检查选择器以找出需要改进的地方。
  • 低权重
    CSS 权重和规则顺序决定着元素所应用的样式。选择器的权重指标可用于度量代码库的权重,以判断代码库是否包含大量高权重的选择器,这些选择器将增加代码的维护成本。CSS Dig 这类工具可以按照选择器的权重为其排序。
  • 更少的文件数量和更小的文件
    应该向终端用户提供合成和压缩过的 CSS 文件——合成可以减少需要下载的文件数量,压缩可以删除多余字符以减小文件体积。这两种处理方法都能提高下载速度,进而减少页面加载时间。