许多开发者撰写关于如何维护 CSS 代码库的文章,但很少有人写他们如何 *衡量* 代码库的质量。当然,我们有像 StyleLint 和 CSSLint 这样优秀的代码风格检查工具,但它们只能帮助在微观层面上防止错误。使用错误的颜色表示法,在已经使用 Autoprefixer 的情况下添加供应商前缀,以不一致的方式编写选择器……诸如此类。
我们一直在寻找改进 CSS 编写方式的方法:OOCSS、BEM、SMACSS、ITCSS、实用优先等。但其他开发社区似乎已经从仅仅使用代码风格检查工具发展到像 SonarQube 和 PHP Mess Detector 这样的工具,而 CSS 社区仍然缺乏比浅层 lint 规则更深入的检查工具。出于这个原因,我创建了 Project Wallace,一个用于检查和强制执行 CSS 质量的工具套件。
什么是 Project Wallace?
从核心来看,Project Wallace 是一组工具,包括命令行界面、代码风格检查工具、分析和报告
以下是这些工具的简要概述。
命令行界面
这允许您在 命令行上运行 CSS 分析 并获取您提供给它的任何 CSS 的统计信息。

Constyble 代码风格检查工具
这是一个专为 CSS 设计的代码风格检查工具。基于 Wallace 生成的分析,您可以设置不应超过的阈值。例如,单个 CSS 规则不应包含超过 10 个选择器,或者平均选择器复杂度不应高于 3。
分析
Extract-CSS 正如其名称所示:从网页中提取所有 CSS,以便我们可以将其发送到 projectwallace.com 进行分析。
报告
Extract CSS 的所有分析都发送到 projectwallace.com,仪表板包含所有数据的报告。它类似于 CSS Stats,但它跟踪更多指标并随时间存储结果并在仪表板中显示它们。它还显示了两个时间点之间的差异,以及许多其他功能。

分析 CSS 复杂度
关于 CSS 复杂度的文章并不多,但 Harry Roberts (csswizardry) 撰写的那一篇 让我印象深刻。其要点是每个 CSS 选择器基本上都是一堆 if 语句,这让我想起了上计算机科学课程时,我必须手动计算 循环复杂度 的方法。Harry 的文章对我来说很有意义,因为我们可以编写一个模块来计算 CSS 选择器的复杂度——当然不要与 特异性 混淆,因为在复杂度方面,这是一个完全不同的问题。
基本上,CSS 中的复杂度可以以多种形式出现,但以下是我在审计代码库时最关注的方面
CSS 选择器的循环复杂度
选择器的每个部分都意味着浏览器需要执行另一个 if 语句。较长的选择器比较短的选择器更复杂。它们更难调试,浏览器解析速度也更慢,并且更难覆盖。
.my-selector {} /* 1 identifier */
.my #super [complex^="selector"] > with ~ many :identifiers {} /* 6 identifiers */
每个规则集中的声明(内聚性)
具有许多声明的规则集比具有少量声明的规则集更复杂。像 Tailwind 和 Tachyons 这样的函数式 CSS 框架的流行可能是由于 CSS 本身相对“简单”。
/* 1 rule, 1 declaration => cohesion = 1 */
.text-center {
text-align: center;
}
/* 1 rule, 8 declarations => cohesion = (1 / 8) = 0.125 */
.button {
background-color: blue;
color: white;
padding: 1em;
border: 1px solid;
display: inline-block;
font-size: normal;
font-weight: bold;
text-decoration: none;
}
源代码行数
代码越多,复杂度越高。编写的每一行代码都需要维护,因此包含在报告中。
每个规则的平均选择器数
规则通常包含 1 个选择器,但有时会更多。这使得难以删除 CSS 的某些部分,从而使其更复杂。
所有这些指标都可以使用 Constyble 进行代码风格检查,Constyble 是 Project Wallace 在其工具栈中使用的 CSS 复杂度代码风格检查工具。在为指标定义基线后,只需安装 Constyble 并设置配置文件即可。以下是我从 Constyble 自述文件直接提取的配置文件示例
{
// Do not exceed 4095 selectors, otherwise IE9 will drop any subsequent rules
"selectors.total": 4095,
// We don't want ID selectors
"selectors.id.total": 0,
// If any other color than these appears, report an error!
"values.colors.unique": ["#fff", "#000"]
}
很酷的一点是,Constyble 在您的最终 CSS 上运行,因此它只在您从 Sass、Less、PostCSS 或您使用的任何其他预处理器完成所有预处理工作后才会执行其操作。这样,我们可以对选择器的总数或平均选择器复杂度进行智能检查——就像任何代码风格检查工具一样,您可以将此 作为构建步骤的一部分,如果存在任何问题,则构建将失败。
使用 Project Wallace 的收获
在使用 Project Wallace 一段时间后,我发现它非常适合跟踪代码复杂度。虽然它的主要设计目的就是如此,但它也是一种发现 CSS 中细微 bug 的好方法,这些 bug 由于代码检查的是预处理后的代码,因此代码检查器可能无法发现。以下是我发现的一些有趣的事情。
- 我停止计算我们冲刺中需要修复网站上颜色不一致的用户故事的数量了。 项目存在数年,人员进进出出:这会导致网站上每个品牌颜色都出错。幸运的是,我们实施了 Constyble 和 Project Wallace 以获得利益相关者的认可,因为我们能够证明我们客户的品牌在较新的项目中是完全正确的。Constyble 阻止我们添加不在样式指南中的颜色。
一个颜色图表证明我们的颜色使用非常准确。只有少数颜色,并且仅限于源自客户样式指南或代码库的颜色。 - 我已经在我以前雇主工作过的所有项目中安装了 Project Wallace Webhook。 每次向项目添加新的 CSS 时,它都会将 CSS 发送到 projectwallace.com,并且会在项目的仪表板中立即显示。这使得很容易发现何时向 CSS 中添加了特定的选择器或媒体查询。
“嘿,那个橙色去哪里了?”来自 projectwallace.com 的一个差异示例。 - CSS-Tricks 在今年早些时候进行了重新设计,这意味着复杂度和文件大小大幅下降。 重新设计非常值得分析。它让你有机会一窥幕后,了解作者如何以及如何更改了他们的 CSS。了解哪些部分对网站不起作用以及哪些新部分起作用,可能会让你了解 CSS 的快速发展。
- 一家总部位于荷兰的大型国际公司曾经在一个 CSS 文件中拥有超过 4095 个选择器。 我知道他们正在积极进军新兴市场,并且必须支持 Internet Explorer 8+。 IE9 在超过 4095 个选择器后停止读取所有 CSS,因此他们的大部分 CSS 在旧版 IE 浏览器中没有应用。我给他们发送了一封电子邮件,他们验证了这个问题并立即通过将 CSS 分割成两个文件解决了它。
- GitLab 目前使用了超过 70 种不同的字体大小。 我很确定他们的排版系统很复杂,但这看起来有点过于雄心勃勃。可能是由于某些第三方 CSS 导致的,但这很难确定。
GitLab 使用的 70 多种独特字体大小的子集。 - 在从其他开发人员那里继承项目时,我会查看 CSS 分析,以便了解项目的难点。 他们是否大量使用了
!important
?规则集的平均大小是否易于理解,或者他们是否在每个规则集中使用了 20 多个声明?平均选择器长度是多少,它们是否难以覆盖?不必诉诸.complex-selector-override\[class\][class][class]...[class]
会很不错。 - 检查代码压缩是否正常的一个巧妙技巧是让 Constyble 检查代码行数指标是否不超过 1。 CSS 代码压缩意味着所有 CSS 都放在一行上,因此代码行数应该等于 1!
- 在我另一个项目中,代码压缩一直出现故障。 我对此一无所知,直到 Project Wallace 的差异显示给我,一堆颜色突然变成了
#aaaaaa
而不是#aaa
。这本身并不是一件坏事,但同时发生了这么多颜色,因此肯定出了问题。快速调查表明我在代码压缩中犯了一个错误。 - StackOverflow 有四种独特的方式来编写白色颜色。 这不一定是坏事,但可能是 CSS 代码压缩器出现故障或设计系统不一致的迹象。
- Facebook.com 在其 CSS 中有超过 650 种独特的颜色。 对于他们来说,设计系统出现故障也开始成为一种可能性。
- 我以前雇主的一个项目显示
input[type=checkbox]:checked+.label input[type=radio]+label:focus:after
是最复杂的选择器。经过仔细检查,我们发现这个选择器定位了一个嵌套在另一个输入中的输入。这在 HTML 中是不可能的,我们意识到我们一定在 CSS 中忘记了一个逗号。没有任何代码检查器提醒我们这一点。 - CSS 预处理器的嵌套很酷,但会导致错误,例如
@media (max-width: 670px) and (max-width: 670px)
,正如我在Syntax.fm 中发现的那样。
对于 Project Wallace 来说,这仅仅是冰山一角。一旦你开始分析你的 CSS,还有很多东西需要学习和发现。不要只看自己的统计数据,也要看看其他人都在做什么。
我将我的 Constyble 配置用作与经验不足的开发人员进行交流的切入点,以解释为什么他们在处理复杂 CSS 代码块时构建失败。与其他开发人员讨论为什么我们要避免或提倡某些 CSS 编写方式有助于知识的传递。它也有助于我保持脚踏实地。不得不向一个只想帮忙的 PHP 开发人员解释我已经做了多年的事情,让我重新思考我为什么以这种方式做事。
我的目标不是告诉任何人 CSS 中什么正确或什么错误,而是创建工具,以便您可以验证什么对您和您的同事有效。Project Wallace 在这里帮助我们理解我们编写的 CSS。
这对具有简单样式表的网站非常有帮助!只是它似乎不适用于使用组件和作用域样式的网站。我是否遗漏了什么,或者分析没有深入到组件样式中?
如果您使用 projectwallace.com/analyze-css,它也应该提取使用 Styled Components 或类似技术生成的 CSS。您是否有缺少某些样式的页面的示例?
嘿 Bart,是的,初始提取似乎引入了所有 CSS。但是,我指的是添加项目,并且“从 URL 获取”似乎只获取了部分 CSS。(相同的站点,不同的结果)也许这里存在我不理解的区别。
似乎存在一些不一致。我将尝试重现它并修复它。您能通过 Twitter 或[email protected]将您尝试分析的网址发送给我吗?谢谢!
你太棒了,Bart。
Project Wallace 非常出色。
虽然我还没有设法对其进行彻底测试,但我发现它是一个很棒的 CSS 分析工具。自从 Flexbox 发布以来,我还没有对 CSS 如此兴奋过。
继续努力。
非常感谢!
太棒了!我大部分时间都是兼职网页开发人员(更像是一种爱好)。(还有人记得 HomeSite 吗?)我一直想要这样的工具。
但是,我花了大约十秒钟就得到了:“用户名应由字母数字字符和连字符组成。”什么,没有下划线?
非常有趣的工具,但我认为你破坏了一些人的花哨 CSS 技巧。
我猜类名
label
不幸,但我在这个选择器中没有看到嵌套的输入。糟糕……我想你是对的!
input[type=checkbox]:checked+.label input[type=radio]+label:focus:after
是完整的选择器,但你是对的。第二个输入位于第一个输入旁边的 .label 内部。无论如何,循环复杂度都超出了图表范围。