我是否应该以编程方式内联所有 CSS 文件以优化页面加载速度?

Should I inline all CSS files programmatically to optimize page load speed?

Google PageSpeed 经常建议 optimize CSS delivery。我想到它会减少网络往返以内联所有 CSS 像这样:

<style type="text/css">

    @{ 
        var bootstrap = File.ReadAllText(Server.MapPath("bootstrap.min.css"));
        var bootstrapTheme = File.ReadAllText(Server.MapPath("theme.min.css"));
        var fontAwesome = File.ReadAllText(Server.MapPath("font-awesome.min.css"));
        var bigfont = File.ReadAllText(Server.MapPath("bigfont.min.css"));
        var bigfontPrint = File.ReadAllText(Server.MapPath("bigfont-print.min.css"));
    }

    @Html.Raw(bootstrap)
    @Html.Raw(bootstrapTheme)
    @Html.Raw(fontAwesome)
    @Html.Raw(bigfont)
    @Html.Raw(bigfontPrint)

</style>

这似乎是解决页面加载缓慢问题的合理解决方案,并将我的 PageSpeed 分数从 88 提高到 95。

暂时把代码风格放在一边,不以这种方式内联所有 CSS 存在哪些技术原因(如果有的话)?

内联所有 CSS 意味着它无法被缓存,因此每个页面加载都将包含所有 CSS 所需的内容,并且当您使用大型库时,这可能真的很多浪费带宽。例如,Bootstrap 大约是 120k。请注意您共享的 Google link 指定以下内容(强调我的):

If the external CSS resources are small, you can insert those directly into the HTML document, which is called inlining.

因此单个页面的加载速度可能会更快,但总体而言可能会更慢。

就我个人而言,我会远离这样做。但是,您可以做的一件事是将所有 CSS 捆绑到一个请求中(您使用的是 MVC,所以这相对简单),因此您只需为 [=17] 额外访问一次服务器=] 并且浏览器请求的所有未来页面都不需要再次请求它们。

评论太长了。在我工作的地方,我们使用 Content Security Policy header directives (specifically style-src) to explicitly prohibit the use of inline CSS. The rationale not to use inline CSS in this case is minimizing the risks of CSS injection for pages created dynamically. OWASP has detailed information about this topic, including exploit samples: https://www.owasp.org/index.php/Testing_for_CSS_Injection_(OTG-CLIENT-005)。如果只向浏览器提供静态内容,应该没有风险。

您误解了 PageSpeed 建议。建议用于小 CSS 文件:

If the external CSS resources are small, you can insert those directly into the HTML document, which is called inlining. [...] Keep in mind if the CSS file is large, completely inlining the CSS may cause PageSpeed Insights to warn that the above-the-fold portion of your page is too large via Prioritize Visible Content.

事实上,文章后面建议了一种针对大型 CSS 文件的平衡方法:内联关键 CSS 和 defer-load 剩余的 CSS 文件。


现在,即使 PageSpeed 在内联大型 CSS 文件后给你一个不错的分数*,它可能仍然是一个坏主意:

冗余

内联 CSS 文件意味着您在页面之间复制 <style>...</style> 标签。这意味着您为后续或重复的页面视图提供冗余数据。冗余数据会占用带宽并增加下载时间。

单独的 CSS 文件以及强大的缓存 headers 让您可以消除冗余。缓存 headers 指示浏览器在第一个页面视图中缓存 CSS 文件,并在后续或重复页面视图中重复使用。

内容与数据

内联 CSS 文件减少了页面上“实际”内容的比例。内联 CSS 文件要求您在内容上方插入 CSS,而我们大多数人都努力将实际内容放在顶部 HTML.

附近

内联 CSS 还会导致浏览器在允许其下载其他资源(例如 JavaScript 和图像)之前下载额外的字节。

压缩成本

如果您的 HTML 页面是动态生成的,那么很可能会以未压缩的形式提供。某些服务器(例如 IIS)和软件(例如 Wordpress)允许压缩动态内容,但与压缩静态内容(例如 CSS 文件)相比需要更多 CPU + 内存。这是您应该将 CSS 保存在单独文件中的另一个原因。

出于上述原因,我会将 CSS 组合、缩小、压缩和缓存在一个单独的文件中,即使是单页网站也是如此。


* 不要与 inline styles

混淆

没有人提到这项技术的预期用例,这绝对不是加载 100% 的 css。相反,此技术旨在让用户认为页面加载速度更快。

当我们讨论让页面加载更快时,真正的目标通常是让页面加载看起来更快。从用户体验的角度来看,这比实际让加载花费更少的时间重要得多。加载整个页面是否需要 500 毫秒并不重要,因为无论如何人类都无法快速解析它。重要的是页面加载的速度。

因此,此技术的正确用法是立即加载使页面正确呈现的绝对必要 css。也就是说,有一些 css 规则可以使图像大小合适,使事物正确浮动,避免在 facebook SDK 完成其业务时页面内容在页面上跳来跳去的可怕外观。该代码需要在标记加载的同一时刻出现。解决方案:内联那个关键的 css.

但绝对不要内联所有 css。如果 css 仅对异步加载的内容进行样式设置,则可以稍后加载另外 100kb。但是如果有页面结构必须在 25ms 之后以正确的形式出现,那么 css 应该被内联。