有很多工具旨在帮助您从项目中删除“未使用 CSS”。几乎每周我都会看到有人分享或推广此类工具。它一定触动了某些开发人员的某种完美和弦。我关心性能,并且知道减小文件大小有利于性能。的确如此。我敢打赌,我们的样式表中肯定存在一些未使用的 CSS,如果我们删除这些 CSS,那将是一次性能提升。没错,会的。我们应该自动化这个过程。额......我不太确定。
一些主要的性能工具,例如 Lighthouse,也都在强调这个想法,以及它如何为您提供 CSS 和 JS“覆盖率”,这当然会告诉您,您正在发布一些不需要的代码。
声称可以帮助您处理未使用 CSS 的工具必须执行分析才能告诉您哪些是未使用的,哪些不是。
以下是执行此分析的一种方法。渲染您网站的一个页面并获取完整的 DOM。然后获取完整的 CSSOM,它可以为您提供 CSS 中所有选择器的数组。遍历这些选择器并在 DOM 中执行 querySelector
以查看它是否匹配任何内容。如果不匹配,则该 CSS 选择器未使用。
很聪明,对吧?!
我认为是。但这种分析描绘了一幅相当有限的画面。
假设分析在页面完成两秒后运行,但有一些 JavaScript 代码在五秒后运行并注入了一个模态框(呃,我知道)。分析将错过该模态框中的 HTML,该 HTML 可能具有样式,因此会错误地将这些样式报告为未使用。
因此,时间是一个因素。希望此分析工具具有一些配置多个时间点的方法。
到目前为止,我们只查看了一个页面。当然,一个网站可能拥有数十个、数百个甚至数千个页面。要完全确定未使用的样式,查看所有页面是最可靠的方法。
多个页面是另一个因素。希望分析工具能够查看您指定的所有页面。也许它可以查看站点地图?
还记得时间问题吗?我们可以将时间视为状态的一种通用形式。还有无数其他可能与状态相关的事物。用户是否已登录?他们使用的是什么计划?他们的信用卡是否已过期,从而显示某种特殊消息?时间/日期/地理位置等情境因素是否会改变状态?实时数据呢?来自 API 的内容呢?
应用程序级状态显然是一个重要因素。希望此分析工具能够触发/设置所有可能的状态组合。
还有交互式状态。点击某些内容后弹出的模态框呢?哪个选项卡处于活动状态?此菜单是打开还是关闭?用户处于哪个滚动位置?这方面有无限的排列组合。想象一下,用户登录七秒后出现一个警告栏,警告用户他们的信用卡已过期,该警告栏包含一个自定义样式的选择菜单,该菜单可以处于打开或关闭状态,但仅在用户设置页面上出现。
此分析工具似乎不太可能处理所有这些可能性。即使进行大量配置、模拟状态和集成测试,它也无法涵盖所有这些的几乎无限的可能排列组合。
然而,我认为这些工具并非毫无用处——它们只是...工具。它们的用途实际上可以是迈向更好代码的积极一步。它们的用途表明好的,我承认,我有点担心我们的 CSS。您可以使用此工具大致了解未使用 CSS 的可能情况,然后结合您对 CSS 代码库的了解做出更明智的决策。或者采取另一项技术步骤,例如 为这些未使用的选择器添加背景图像 并检查服务器日志以查看它们是否被命中。
需要说明的是,这个关于未使用 CSS 的整个想法是我们行业正在经历的 CSS-in-JS 浪潮的一部分。如果所有样式都作为组件的一部分编写,那么基本上就没有未使用 CSS 的问题。组件要么被使用,样式随之而来,要么不被使用。如果您特别担心未使用 CSS 的风险,这一点本身就可能促使您转向 CSS-in-JS 工具。
还需要说明的是,这种 DOM 和 CSSOM 分析技术只是检查未使用样式的一种可能方法。如果您拥有某种可以分析所有模板、样式和脚本的 高级工具,那么它也可能确定未使用样式。我们在最近的 与 Chris Eppstein 合作的 ShopTalk Show 集中讨论了这一点。
根据我的个人经验,性能膨胀是由网站引入的所有第三方资源引起的(例如,根据 Privacy Badger,此网站调用了 21 个资源)。如果 CSS 是静态的并且具有适当的缓存生命周期,那么它只有在未被缓存时才可能成为一个因素。如果您在包含 CSS 文件时包含其上次修改日期的时间戳(使用 mod_rewrite 提供实际文件),那么您可以发送一个标头,指示将其缓存一年,但对 CSS 的任何修改都会立即提供服务,因为时间戳已更改。
无论如何,当然,您永远不会再次使用的 CSS 应该被删除,但是由于它当前未被使用而自动删除——这是一个坏主意。
赞同 +1
您的想法正是我使用 Lighthouse 等工具时担心的。我的结论是,我们无法在运行时检测未使用 CSS,唯一的方法是在之前检测。如果您使用 Webpack 等模块打包工具,我编写了一个插件可以帮助我们实现所需的功能
https://github.com/MQuy/es6-css-loader
https://github.com/MQuy/webpack-deadcode-plugin
如果您想详细讨论,请私信我。
基于组件的资源,如前所述,似乎是未来的发展方向——也许不仅仅是在 CSS-in-JS 领域,而是在开发的各个方面?
这与关键样式和延迟样式相一致,在关键样式和延迟样式中,您有一个对于网站显示至关重要的框架样式表,但所有其他样式表仅在需要时才引入,并在过期后“清除”。
一旦资源加载到缓存中,就不必一遍又一遍地下载它,我个人认为,在 LiFi 和 3.14159265358979323846264338327950288419716939937510582097494 G 蜂窝网络等问题仍然存在的情况下,仅下载该页面当时所需的内容是未来的发展方向! ;-)
不过,文章中所有观点都很好,Chris,再次感谢您如此清晰地表达了我一直在思考的内容!#h5yr
这就是为什么编译器框架越来越流行的一个原因,这些框架确实可以安全地删除未使用 CSS。OptiCSS(文章中提到的 CSS Blocks 的配套工具)就是一个可以做到这一点的工具,因为它了解了您的模板和 CSS 的所有信息。
Svelte(免责声明:我是主要维护者)是另一个例子。因为它分析组件的 CSS(使用 css-tree 在组件标记的上下文中解析),因此它能够消除输出 .css 文件中的未使用样式,不会出现误报,并且误报很少(即,它可能会在某些极端情况下保留某些样式,但绝不会错误地删除样式)。这是一个演示,让您了解其工作原理。
看起来 Rich 粘贴了一个本地机器链接而不是演示链接。我相信这是正确的链接
https://svelte.technology/repl?version=2.7.2&gist=510aaa876132392e69caab6e91f91cf2
啊,我真是个傻瓜——谢谢 Louis,这是正确的 URL!
我认为防止未使用 CSS 累积的一个好方法是为每个组件和视图创建不同的样式表,以便在从项目中删除标记文件时,相关的 CSS 也被删除。
我通常通过在 styles 目录下创建一个与 views 目录类似的文件系统结构来实现这一点,并且每个视图文件都有一个对应的 LESS 文件。然后将所有内容折叠成几个入口点样式表,其中所有内容都将被导入。
然后,只需删除不再有视图的样式表即可。
同意!
太棒了……我喜欢这些“有用的工具”如何删除字体或背景颜色,当它设置为默认的黑白时,对吧?只是没有所谓的默认 CSS 颜色。所有这些都与浏览器、操作系统和用户设置相关,因此您永远无法设置其中一个而不设置另一个,否则最终会得到黑底黑字或白底白字以及类似的不可读组合。始终为所有元素设置两种颜色,它不是未使用的 CSS!
是的,我的操作系统设置为黑底白字,并且每个主要的浏览器都能直接识别。
想象一下,你正在编写 CSS 用于一致的排版,然后这个工具删除了你的
blockquote
样式,因为当前页面文章中没有引用。