糟糕!我们的样式表只会越长越大!(仅追加样式表问题)

Avatar of Chris Coyier
Chris Coyier

DigitalOcean 为您旅程的每个阶段提供云产品。立即开始使用 200 美元的免费额度!

如今,这确实是一个令人担忧的问题。我从很多很多开发者那里听说了这个问题。他们的项目一年又一年地进行着,而他们似乎一直在做的事情就是向他们的 CSS 中添加内容,从未删除。这不仅仅是一种感觉,我之前也与跟踪此类硬数据的公司谈过。在跟踪他们样式表大小的五年时间里,它的大小一直在不断增加。

这可能因几个原因被认为是有问题的

  1. 文件越大,性能越差
  2. 开发者害怕 CSS

在我看来,#2 比 #1 重要得多。如今,CSS 的整体文件大小可能相当小,与图像资产甚至 JavaScript 负载相比。花哨的工具和互联网速度不断加快,可能会使 #1 变得不那么重要。

但害怕自己的样式是一个更大的问题。

“害怕”通常不是用来描述这个问题的,但我认为这就是问题的本质。人们经常谈论 CSS 的全局特性如何成为问题,或者说“CSS”中的中间“S”是唯一值得保留的。

“未使用的 CSS”

这个故事的一部分当然可以是关于删除项目中被确定为“未使用”的 CSS。我知道人们对这种工具的需求非常强烈。我觉得有些开发者几乎是急切地想要将他们的 CSS 通过某种高级工具进行处理,以去除任何不需要的东西。

这让我有点担心。这感觉就像在说:“是的,我害怕我们的样式表。我不想理解它们,我只是想要一些东西来帮我修复它们。”

以下是听说的一家公司是如何做的

  1. 他们向页面上的一小部分用户注入了一个脚本。
  2. 该脚本会查看 CSSOM 并找到该页面 CSS 中的每个选择器。
  3. 它还会运行一个 querySelectorAll(“*”) 并找到该页面上的每个 DOM 节点。
  4. 它会比较这两个集合,并找到所有似乎未使用的选择器。
  5. 为了获得最佳结果,它会在随机时间段后,针对随机用户集,在随机条件下触发此脚本。即使这样,它也需要在很长一段时间内收集大量数据。
  6. 在运行足够长的时间后,就会有一组似乎未使用的 CSS 选择器。
  7. 为了确保,会将唯一的背景图像应用于所有这些选择器。
  8. 应用这些图像并等待一段时间后,检查服务器日志以确保从未访问过这些图像。如果访问过,则表示该选择器被使用,必须保留。
    最终,可以安全地从 CSS 中删除未使用的选择器。

哇!删除一些 CSS 需要花费大量工作。

但正如你所想象的那样,这相当安全。想象一下只检查**一个页面**的 CSS 覆盖率。你肯定会发现很多未使用的 CSS。一个页面,在一个特定的状态下,并不能代表你的整个网站。

网站有多个页面。JavaScript 在上面运行,影响 HTML。用户可能会登录,以不同的状态显示内容。网站上会发生动态的事情。为了真正了解哪些 CSS 被使用,你必须测试每个可能的页面,以及每个可能的交互排列,这是一个非常大的工作量。我相信你可以想象一些 CSS,它只适用于已登录用户在订阅过期后登录更新信用卡的特定选择菜单,而更新操作发生在一个模态窗口中,其中包含一个表单,由于卡是美国运通卡,因此以某种方式显示。

尽管如此,还是有一些工具声称可以帮助你找到未使用的 CSS

Chrome 拥有一个“覆盖率”面板(在我编写本文时,它在 Canary 版本中),可以告诉你哪些 CSS 被使用

它非常棒,你可以点击录制按钮,四处点击并执行大量操作(甚至更改页面),它会继续分析使用了多少 CSS。然后你可以看到 CSS 旁边红色或绿色的条形,了解哪些被使用或未被使用。

它存在与我之前描述的相同问题,即你只是四处点击不足以保证覆盖率。你很可能会错过一些边缘情况,如果你根据不完整的测试做出删除 CSS 的决定,你将给自己带来麻烦。

还有其他工具试图帮助删除未使用的 CSS,UnCSS可能是最受欢迎的。

UnCSS 做了一些聪明的事情,例如允许你列出一系列要一起测试的 URL,提供要应用的媒体查询,并运行 JavaScript。以下是他们的示例配置

var uncss = require('uncss');

var files   = ['my', 'array', 'of', 'HTML', 'files', 'or', 'http://urls.com'],
    options = {
        ignore       : ['#added_at_runtime', /test\-[0-9]+/],
        media        : ['(min-width: 700px) handheld and (orientation: landscape)'],
        csspath      : '../public/css/',
        raw          : 'h1 { color: green }',
        stylesheets  : ['lib/bootstrap/dist/css/bootstrap.css', 'src/public/css/main.css'],
        ignoreSheets : [/fonts.googleapis/],
        timeout      : 1000,
        htmlroot     : 'public',
        report       : false,
        uncssrc      : '.uncssrc'
    };

uncss(files, options, function (error, output) {
    console.log(output);
});

我仍然担心这将难以配置(并保持配置),以至于它能提供 100% 的测试覆盖率。每次你编写一个新的 CSS 规则时,都需要确保它不会在这里触发误报。也就是说,假设你实际上使用此工具来删除 CSS。

更不用说,虽然它确实执行 JavaScript,但它没有模拟交互。

另一种方法:框架

想象一下,你使用了一个 CSS 框架,它提供了你想要应用的每个实用的样式。与其编写 CSS,不如应用框架应用的类来完成你需要做的事情。你现在将你的 HTML 类与这个框架紧密地绑定在一起,但你解决了不断增长的 CSS 问题。多年来,你的 CSS 将保持不变。

我不是 Tachyons 的专家,但对我来说似乎就是这样。在你习惯使用它之后,你会很快地编写出你需要的内容,并且还有一个好处,那就是这个几乎不会改变的静态 CSS 文件,没有人会害怕它。

这属于一个被称为 原子 CSS 的类别,其中有 许多参与者。原子 CSS 的一个版本是“程序化”的,你使用特殊的类和一个处理步骤来生成最终的 CSS。这样做的目的是,你现在不需要发送一个静态的 CSS 框架,而只需要发送你真正需要的少量 CSS。

John Polacek 最近 写到了这一点。他发现自己既遭受了 CSS 增长问题的困扰,也发现原子 CSS 不仅停止了这种趋势,而且还逆转了它。

即使是像 Bootstrap、Foundation、Materialize 或 Bulma 这样的框架也适合这里。关键是,如果你坚持使用框架,你就永远不会陷入害怕自己 CSS 的那种不理想的状态。

JS 中的 CSS

在 JavaScript 中管理样式(推荐阅读)也可以帮助解决这个问题。完全作用域于特定模块的样式,本质上易于删除。不需要模块,就不需要样式。

别太担心

我发现所有这些东西都很有趣,值得观察和思考。正如人们常说的:网络是一个很大的地方。我们每个人都有自己独特的情况。这个问题会影响我们中的一部分人,而且我敢说,可能只是一小部分人。

如果你不特别担心 CSS 的大小,也不特别害怕它,那就太好了!我大多数项目也是这样。

我只是有一种感觉(实际上是一个 预测),CSS 的未来是模块化的

当我们编写样式时,我们总是会做出选择。这是全局样式吗?我是否故意将此样式泄漏到整个网站?或者,我是否正在编写特定于此组件的 CSS?CSS 将在这两者之间一分为二。特定于组件的样式将被作用域化并与组件捆绑在一起,并在需要时使用。

我还不确定这方面的主要工具是什么,即使有的话。