以下是来自 Ben Edwards 的客座文章。我看到 Ben 在推特上发布了一条关于一个简单的 Sass @mixin 的推文,该 mixin 允许您将 CSS 的一部分指定为“关键”——其理念是先加载该关键 CSS,然后延迟加载其余的 CSS。这是一个聪明的想法,并且在网页性能人群中越来越受欢迎。我认为我应该让 Ben 为我们更详细地介绍这些想法。
Google PageSpeed Insights 和我的网页;这简直是天作之合,直到情况发生变化……PageSpeed 开始告诉我需要优化 CSS 传递,我的 CSS 文件是渲染阻塞的,我的页面上所有视窗以上的元素在那些文件加载之前都无法渲染,并且我应该将那些文件中的关键部分直接内联到我的 HTML 中。
回家去吧,PageSpeed
,我哭喊着,谁会想要在自己的 HTML 中看到一堆 CSS?我是一个合法的专业人士,你知道我有自己的工作流程的!
我嘲笑着。
我一直坚持我的立场,直到我看到了以下这条推文
我想看到一个类似于 CSS Zen Garden 的网站,但是开发人员试图让
同一个响应式网站在 webpagetest.org 上获得更高的分数
Scott Jehl
我一直致力于让我的网页在 webpagetest.org 上获得尽可能高的分数,这需要改变工作流程,那么为什么我不应该为 PageSpeed 改变呢?现在,如果您已经在使用 Google 的 mod_pagespeed 模块,那么您可以放轻松,并给自己一个拥抱,因为 该模块已经为您搞定了。对于像我一样没有使用该模块的人来说,以下是我的方法。
以下是科学原理
为了解决这个问题,我首先需要了解 PageSpeed 想要告诉我什么。外部样式表(读取那些通过 link
标签包含的样式表)是渲染阻塞的。这意味着浏览器在所有 CSS 下载完毕之前不会将内容绘制到屏幕上。再加上这样一个事实,即渲染页面所需的數據量如果超过了初始拥塞窗口(通常为压缩后的 14.6kB),则需要在服务器和用户浏览器之间进行额外的往返。所有这一切都会导致额外的网络延迟,对于使用高延迟网络的用户(例如移动设备用户)来说,这会导致页面加载的重大延迟。
PageSpeed 的建议是将您的 CSS 分成两部分;一部分内联,负责为视窗以上的元素进行样式设置,另一部分可以延迟加载。现在,在我们纠结折疊是否存在之前,我们不妨先同意,任何能够更快地将数据传输给用户的方法都是一件好事,对吧?
确定什么是关键的
确定 CSS 中哪些部分是关键的需要检查我的网页在“移动设备”和“桌面”尺寸下的情况,然后对视窗中可见的元素应用的 CSS 规则进行截图。这似乎是一项艰巨的任务,但别担心,一些非常聪明的人来帮忙了
- Paul Kinlan 创建了一个 书签/Chrome 开发者工具片段 来帮助完成这个过程
- Scott Jehl 也创建了
它也以 Node 模块 和 Grunt 任务 的形式提供 - Penthouse 由 Jonas Ohlsson 创建,它以 Node 模块、Grunt 任务 和 在线工具 的形式提供
使用检查结果,我现在需要修改我的 HTML 以非渲染阻塞的方式加载我的 CSS。
异步加载,摆脱烦恼
假设我的一个 HTML 文档如下所示
<html>
<head>
<link rel="stylesheet" href="things.css">
</head>
<body>
<div class="thing1">
Hello world, how goes it?
</div>
...
<div class="thing2">
Hey, I'm totally below-the-fold
</div>
</body>
</html>
假设 things.css
包含以下内容
.thing1 { color: red; }
.thing2 { background: green; }
使用检查结果,我现在可以在 head
中内联关键的视窗以上部分的 CSS,如下所示
<html>
<head>
<style>
.thing1 { color: red; }
</style>
</head>
<body>
<div class="thing1">
Hello world, how goes it?
</div>
...
将它与 Filament Group 的 loadCSS 结合使用,我可以异步加载其余的视窗以下的 CSS,如下所示
...
<div class="thing2">
Hey, I'm totally below-the-fold
</div>
<script>
/*!
Modified for brevity from https://github.com/filamentgroup/loadCSS
loadCSS: load a CSS file asynchronously.
[c]2014 @scottjehl, Filament Group, Inc.
Licensed MIT
*/
function loadCSS(href){
var ss = window.document.createElement('link'),
ref = window.document.getElementsByTagName('head')[0];
ss.rel = 'stylesheet';
ss.href = href;
// temporarily, set media to something non-matching to ensure it'll
// fetch without blocking render
ss.media = 'only x';
ref.parentNode.insertBefore(ss, ref);
setTimeout( function(){
// set media back to `all` so that the stylesheet applies once it loads
ss.media = 'all';
},0);
}
loadCSS('things.css');
</script>
<noscript>
<!-- Let's not assume anything -->
<link rel="stylesheet" href="things.css">
</noscript>
</body>
</html>
未来的工作流程
好消息!PageSpeed 很高兴!它不再抱怨渲染阻塞的 CSS,并对视窗以上的内容得到应有的优先级感到满意,但在当今的 CSS 预处理器和前端工具的世界中,像上面这样的手动流程是行不通的。
自动化的方式
对于那些希望找到一种类似于 mod_pagespeed 的自动化方式,并且也熟悉 Node 的人(对于那些不熟悉的人表示歉意,但在 Clock,它是我们所做的一切的重要组成部分),您一定会想要了解 Penthouse 和 Addy Osmani 的 实验性 Node 模块 Critical,它们都提供了一种方式来内联或操作关键 CSS,这些 CSS 是通过 PageSpeed API 确定的。虽然完全自动化的工作流程听起来很完美,但目前让我感到困扰的一点是,这些工具没有解决内联的 CSS 规则在视窗以下的 CSS 下载完毕后会被再次提供的问题。从尽可能少地向用户发送数据的角度来看,这感觉是一种不必要的重复。
CSS 预处理器来救援
在我看来,使用您最喜欢的 CSS 预处理器来编写视窗以上和视窗以下的 CSS 似乎是理所当然的,也是 Clock 的前端团队目前正在尝试的方法。
新的项目非常适合这种方法,关键 CSS 和非关键 CSS 可以通过一些结构良好的 @import
规则来编写
/* critical.scss - to be in-lined */
@import "header";
/* non-critical.scss - to be asynchronously loaded */
@import "web-fonts";
@import "footer";
如果您的部分不适合这种结构,那么 Team Sass 的条件样式 Compass 插件 Jacket 将非常有用。例如,如果您的部分 _shared.scss
包含了视窗以上和视窗以下元素的规则,则关键规则和非关键规则可以被 Jacket 这样包装起来
@include jacket(critical) {
.header {
color: red;
}
}
@include jacket(non-critical) {
@include font-face(...);
...
.footer {
color: blue;
}
}
然后,critical.css
和 non-critical.css
可以按如下方式进行编辑,以生成相同的 CSS
/* critical.scss - to be in-lined */
$jacket: critical;
@import "shared";
/* non-critical.scss - to be asynchronously loaded */
$jacket: non-critical;
@import "shared";
这种方法也与社区中许多人以组件级别而不是全局位置来编写媒体查询的方式相一致,并且可以用于在组件级别定义关键和非关键 CSS 规则。
我们仍在研究这些内容
虽然 PageSpeed Insights 网页版更新 已经快一年了,但我认为关键 CSS 和优先加载视窗以上内容的话题在过去几个月才开始得到广泛关注。
我希望通过向您提供一些关于我处理关键 CSS 编写方式的见解,能够激励您将其融入到您的工作流程中。并且请密切关注上面提到的工具,因为大多数工具都处于开发的早期阶段,我预计未来会有令人兴奋的变化。
我认为将此问题视为“关键与非关键”而不是“页面折叠以上”的方式更可取。“页面折叠以上”有点暗示“让我们确保网站顶部具有所有必要的样式以使其完整,而底部内容可以稍后处理”。也许这可以接受,但我认为这比将 CSS 分成“关键与非关键”更难编写和维护,在这种情况下,您可以根据需要进行选择。也许您可以将页面顶部的某些内容标记为关键,但还可以将任何布局或排版相关内容标记为关键,这样页面在其余样式加载时,其结构会保持稳固、可用且不会出现跳动。
“页面折叠以上”的加载特性是我最初否定这种技术的原因之一——我第一个会争辩说,传统意义上的“页面折叠”并不存在,因此将它视为关键与非关键是我心中所持的观点,甚至将我的 CSS 文件相应命名。
此外,文章中我在“移动”和“桌面”尺寸行上进行检查的模糊性是由于 PageSpeed Insights 处理大小和启发式方法,实际上并没有提供一组特定的尺寸来进行测试,实际上需要看什么对您、您的网页以及您的工作流程有效。
谢谢,但我希望您能提供一个网址,我可以证明这些措施除了 webpagetest.org 的分数之外产生了实际的影响,而 webpagetest.org 的分数只是一种衡量性能的启发式方法。
为什么不简化您的 CSS,让许多这些问题变得无关紧要呢?无论 webpagetest 说些什么,复杂的 CSS 无法在所有设备上良好呈现。
值得一提的是,webpagetest.org 在移动设备可用性方面的评分为 60%(红色!!)。对于一个本质上只是一个带有提交按钮的表单输入的网站来说,这相当荒谬。
您看到了问题吗?
恐怕这是 CSS/HTML 架构宇航员进行的更多自我陶醉。
这纯粹是恶意攻击。已掩埋。
仅仅因为您不同意,并不意味着他是一个恶意攻击者。只是说…
在我看来,这就是它读起来的方式,而我担心这是我的房子。关于 webpagetest.org 自身得分很差的观点有点疯狂。这就像说一把奶酪刀在三明治里尝起来不好吃一样。
关于没有提供前后结果的观点,您说得有道理。在未来一周左右的时间里,我将把此更改应用于 Clock 的网站后,再进行跟进。并且同意,复杂的、编写糟糕的 CSS 无法通过这些技巧来解决,这需要与尽可能多的性能增强措施相辅相成,因为仅仅使用内联 CSS 无法使网站快速。但关于 webpagetest.org 得分很差的观点无关紧要,但是如果您对遵循其自身建议充满热情,请参与进来,看看他们是否希望有人帮助他们——http://www.webpagetest.org/about
您好,Ben——感谢您对此进行回复。我期待着实际的之前和之后的结果,也许会在一篇后续文章中发布。
我不确定 Chris 今天怎么了(一篇文章说“不聪明”,这篇文章说“有点疯狂”(他完全没有抓住重点——他们甚至没有遵循自己的迂腐建议!),但是的,这是“他的房子”,他可以随意称呼别人。
感谢他只掩埋了这些帖子,没有删除它们 :-)
这会变得多么复杂?“页面折叠以上”取决于视窗,对吧?叹息
此外,我不喜欢内联 CSS 以及以这种方式拆分样式表的想法。一直以来,都是关于将设计与语义 HTML 分开的。现在 Google 告诉我们再次将其组合在一起吗?不。真的不。
我同意“页面折叠以上”是任意的,难以定义,因此在这里不太有用(请参阅我的第一个评论)。但仅仅因为你决定不喜欢它而把它一笔勾销,这很奇怪。这是一个新的想法,可以提高网站的速度,并且这里介绍了工具来帮助减轻痛苦。欢迎您持怀疑态度或提出批评,但闭目塞听并不明智。
正如我在文章中所说,我对此也很怀疑,事实上,Google PageSpeed Insights 已经更新了将近一年,开始报告这些内容。重要的是不要在尝试之前就将其否定,并从以下角度看待它:您为提高分数所做的一切都将对您的用户有利。但它实际上取决于个人喜好和工作流程——决定您想做多少,找出对特定网站有效的方案,以及您需要如何改变工作流程以使其在将来更容易。
Chris,这不是你最好的回复之一。
在我看来,Lars 确实持怀疑态度并提出批评,并且并没有“闭目塞听”。带有攻击性的民间说法“这不明智”也不具有建设性。如果你问我,他对“页面折叠以上”术语的保留比这更有意义。
这通常是一个很棒的博客,但这篇文章和你的评论都不尽如人意。感谢您的倾听。
关于这一点,没有任何内容表明内联样式或会损害您的创作能力。
这读起来就像闭目塞听。
首先,Ben,文章写得很好,希望更多类似的文章!
我喜欢这项技术,但这个概念让我有点害怕。这是否是在创造更好的用户体验,还是仅仅是在获得更好的分数(这是一个很棒的教育挑战)。无论哪种方式,用户都知道移动网站不会立即加载,而且可能并不在意。即使在 Wi-Fi 上,移动设备上的网站加载速度也很慢,因为布局和内容变得越来越复杂。此外,我想知道 Mobile Chrome 的带宽管理(或预压缩)会如何影响这一点?我认为这会使这个问题变得多余。但是,如果出现需要在页面折叠以上内容立即加载的情况,那么知道有解决方案很好。预处理器 FTW
一些前后对比视频会很不错。不过,市面上已经有一些非常棒的演示。
来自 这里
感谢 Simon
我同意,这是一个可怕的概念,而且将 CSS 放在它自己的文件之外,而我们已经习惯了将它放在那里,这似乎也很脏。最终,这是为了创造更好的用户体验,我们不应该依赖用户期望移动设备上的体验很慢,如果需要通过在线工具的分数来进行一些游戏化,我愿意这样做,正如你所说,教育是关键,Chris 和我都认为这很有可能在未来几个月内得到更多关注(密切关注 Filament Group 的人,因为他们在性能领域取得了重大成就!)。
关于 Mobile Chrome 的观点很有趣,当我在 clock.co.uk 上实现上述更改时,我会确保进行测试并报告。我的初步想法是,内联 CSS 会使渲染速度更快,而不是变得多余,但我将在获得结果后分享我的发现。
当我看到它是在编写代码以在性能测试中获得更好的性能时,这让我感到害怕,当然,网络的美丽之处在于每个网站都不一样(每个客户也是如此),因此虽然这个解决方案非常具体,但它展示了一种新技术。它甚至可能导致浏览器供应商以及未来网络规范的创新——为我来说,首先提供关键 CSS 的想法是全新的(除了在模块等中内联加载 CSS 块)。
如果你能找到完美的例子,那会是一个很棒的演讲!
HTTP 2.0 又名 SPDY 将支持“服务器推送”,这意味着服务器可以与 HTML 并行将 CSS 文件发送到浏览器。我希望这会使“内联 CSS”技巧过时。
听到这个消息很有趣。看看它与内联 CSS 结合起来是否会更快!?
对我来说,HTTP2 是正确的答案。
我们需要让我们的工作更轻松的技术。我觉得为了性能而进行如此多的黑客操作最终会让我们发疯。至少就我而言,我知道这会让网页开发失去所有乐趣。
它还会淘汰 JavaScript 文件的合并,简化您的构建过程并更好地利用缓存。
好文章。感谢,Ben。当我有机会实施它时,我想我会走这条路并使用 cookie 来确保异步 CSS 文件在未来的访问中被缓存:https://github.com/filamentgroup/enhance#a-fully-configured-head-setup-for-enhancejs
感谢 Kyle,并感谢你的链接。我不得不承认,Filament Group 最近发布了许多很棒的东西,这导致我在文章最后时刻添加了一些内容,但这篇文章却漏掉了:)
使用“页面折叠”一词就像在响应式网页设计这场战争中后退了一步。这是一个旧的报纸/印刷术语。使用它,你是在鼓励其他开发者使用它,只会使事情更加复杂。没有页面折叠。
看到这篇文章中充斥着这个词,让我想要完全抛弃这篇文章,因为我和传统的印刷设计师进行过很多关于这种错误认知的对话,即存在页面折叠。
我尊重你想要做的事情,我感谢你的才华和你花在撰写这篇文章上的时间,但请认识到这个词如何会阻碍 RWD 的发展。尤其是在代理机构,那里充斥着试图学习网页设计基础知识的传统印刷设计师。
无论使用什么词,是“页面折叠”还是“视线”:-)
在我上网的经验中,加载网页,如果我能够尽快看到一些内容,会产生很大的差异。无论是什么内容,只要我能够尽快与页面互动,就会对我的浏览体验产生影响,并且肯定会影响我的挫败感和“跳出率”,越快越好。
响应式设计只会让它更复杂,因为有些元素可能无法确定它们是否会出现在某些用户的视线范围内。
有些网站选择最后加载所有 CSS,这对我不起作用,因为只看到文本/HTML 版本会令人困惑。因此,这篇文章,它是一个很棒的折衷方案:-)
嗨,Erik
当我写这篇文章时,我知道使用“页面折叠”这个词可能会引起争议,这是我最初看到这些建议时不假思索地拒绝它们的主要原因。但是,由于这是 PageSpeed Insights 使用的词语,我觉得使用它也很重要。
我也是响应式网页设计的倡导者,并且我永远不会主张设计时要考虑“页面折叠”,就像你所说,它根本不存在作为度量单位。
但是,当谈到资产交付时,如果考虑任意“移动”和“桌面”视窗及其任意“页面折叠”,并努力确定网站页面上的关键元素和非关键元素,以及尽力尽快交付渲染这些元素所需的资产,这将有利于所有用户,无论他们的确切设备尺寸如何。
“关键 CSS”不同于“页面折叠 CSS”。
关键 CSS 是你现在需要显示页面所需的所有东西。这可能是页面顶部的东西——比如你的页面很长,有一个很花哨的页脚,那么你可以延迟页脚 CSS。但它也可能是用于交互的 CSS,比如点击小部件创建覆盖层。
把它想象成显示页面初始状态所需的 CSS。用户需要一些时间与页面交互——要么滚动页面,要么激活某些东西——你可以利用这段时间在后台下载剩余的 CSS。
这是否值得麻烦取决于你的网站(以及你/你的团队)。如果你有一个简单的设计,CSS 量很少,并且组织良好,那么也许使用这些花哨的技巧并不值得。但是,如果你有大量的小部件 CSS 膨胀,它可能会产生很大的影响。
当然,优化 CSS 性能最有效的方法是少写 CSS。;-)
完全同意少写 CSS 是优化 CSS 最有效的方法,我并不是在主张任何人应该认为他们仅仅通过实施这篇文章中的更改就完成了工作,而没有尽可能多地进行优化、压缩和合并。
以我自己的网站为例,它只有少量 CSS,加载速度已经很快。但是通过内联所有 CSS 并异步加载网络字体,我已经能够进一步减少加载时间。
是的——我认为这是一个很好的技术,这是我读到的关于它的最好的文章。内联关键 CSS 很聪明。
我的评论更多地是针对“没有页面折叠”的回复。它不仅仅是关于页面折叠;正如你在开头所说,人们对这个词很敏感,并且开始了一场(大部分)无关的讨论。
当然你说的对——几乎任何网站,即使是 CSS 很少的网站,都可以在使用这种技术的情况下提高性能。你的网站可能并不“需要”这种优化,但是由于你付出了额外的努力,你让它变得更快了。
我想说的是,你总能调整性能。你走多远取决于你的网站的性质,以及你有多少时间/技能花在这上面。
我不急于在我的网站上实施它,因为我认为目前对我来说并不值得。但我很高兴将来能够参考这篇优秀的文章!
嗯,很多人讨厌这个。但我认为这只是因为它很困难。
确定页面折叠,我们很久以前就放弃了,然后必须使用第三方工具来确定哪些 CSS 用于页面的那一部分,然后必须将这些 CSS 分离到内联中——在使用 Sass 之类的 CMS 中构建的网站上无法自动完成的事情。
如果需要以有意义的方式更改 CSS,那么就会想起“筋疲力尽”这个词。
我刚刚在我的公司最新网站之一上运行了 Scott Jehl 的脚本,它确定了整个样式表(按字符数计)的 50% 是页面折叠内容所需要的。要分离出来并内联,这真是太多了。部分原因是重置样式——没有人需要在他们的演示中提到这些样式。
mod_pagespeed 看起来是最简单的方法。
这篇文章可以完全重写,以删除页面折叠的引用和任何关于页面速度的引用,但建议的解决方案是针对那个问题的,并不适用于每个网站。
然而,这项技术实际上非常有见地,并且有很多用途。它可以被用来只加载与初始视图或第一页相关的 CSS,或者像 Mike 所建议的那样,只加载与关键功能相关的 CSS。想象一下,如果你有一个复杂的网络应用程序,它有一个相对简单的启动页面,并且没有共享太多样式,甚至是一个包含大量未在首页上使用的 CSS 动画的动态网站——如果你为它们添加供应商前缀,它们会变得很大!
人们经常建议所有 Javascript 都应该加载在 DOM 的末尾,但这通常不切实际,你仍然需要一些 Javascript 在头部。对于关键 CSS 和非关键 CSS 来说也是一样,即使它仍然是整体代码的 50%。这篇文章让我了解了一种我以前从未听说过的技术,很高兴看到它将如何发展。
这是这篇文章没有真正提到的一点,从我读到的内容来看。对于“页面折叠”这个词有很多争论,但如果将其简化为第一页会更容易。这就是 mod_pagespeed 的工作方式。
在很多情况下,它比商业网站更有用,但它是一种需要花费额外时间才能真正完成的技术——尤其是如果网站是在 CMS 中构建的,在 CMS 中注入代码不像修改 HTML 文件那么直接,如果将来有任何 CSS 发生更改——我认为这就是很多人不喜欢它的原因。
如果它能像许多其他增强功能一样自动完成——或者为如此小的额外努力提供如此切实的益处(假设并非每个人都能使用 mod_pagespeed 之类的东西),我认为不喜欢它的一半人就不会不喜欢它了。
文章很棒,很有趣——希望阅读更多。
关键元素和非关键元素的嵌套在这里感觉很臃肿。一个(可能是 Compass——因为 Sass 据我所知无法做到这一点)插件可以在这里简化生活。
所以,与其写
可以写
插件可以检测
{}
之间需要什么。我也有同样的想法,但后来我想到了源文件中会有多少个
!critical
和!non-critical
,我认为这会是一团乱麻。我认为关键部分通常不会在特定属性/值上,而是更多地是在选择器级别上,所以也许可以这样写:
.header {
color: red;
margin: 2em;
border: 1px solid #000;
}!critical
可以工作,虽然我不太喜欢这种语法。
我也想表达我对“页面折叠”这个词的负面感受,因为我们都知道它是一个移动的目标,不值得追逐或参考。
普通用户知道网站需要加载,并且由于他们习惯了在各种速度下加载(由于使用不同的设备访问互联网),因此在网站加载时间平均的情况下,他们不太可能离开页面。我很难理解使用这种策略有什么实际的好处。
我完全同意,这是一种非常危险的想法。对我来说,这感觉像是防御性的自我验证。感觉就像“别担心性能,人们理解网站加载需要时间,无论我现在做什么都行。”而你将通过继续经营企业来得到验证。
然而,还有一个替代路线:关心性能,学习新东西来让网站更快,收获速度带来的回报。
我理解你的担忧。我的意思是,不要为了微不足道的效率和得分而牺牲代码的完整性。在大多数情况下,成本大于收益,除非你的网站本来就很低效。如果你获得了大量的速度提升,那么可能别的地方出了问题。
很棒的文章,Ben!看到我的一个插件被用于我从未想过的一些智能操作,真是令人兴奋。
我真的很喜欢关键和非关键与页面可见区域的概念。
这是一个对关键 CSS 的精彩解释,它解决了我们都忽视的“页面可见区域”性能问题。有时,这一切都像是构建超级创可贴,却忽略了我们伤口的根源。
但我现在被说服了。事实上,我目前正在对一个网站进行翻新,并使用了一些这些技术,我将汇报结果。我们将在内容繁重的页面上渲染内联 CSS,这些页面的分析结果表明它们也是用户的第一站。页面的组件将告诉编译器需要哪些 CSS。我们还在尝试异步地将网站最常用的 CSS 加载到一个字符串化的 localStorage 对象中,这也有可能让各个组件也把它们的 CSS 放到那里。这是一个利用我们每个来源 5MB localStorage 的奇怪方法。你有没有尝试过类似的技术?后处理优化技术是否像这样稳定?
抱歉,请看我下面的评论。
loadCSS
似乎是对信息的无谓重复,即文件名,并且需要为每个你可能在链接上使用的属性进行扩展。作为一个零阶近似(我只在 FF 和 Chrome 中进行了简短的测试),如何将class="stylesheet deferred"
放到你的 noscript 标签上,并按照以下思路进行操作使用 localStorage 是我知道 Scott Jehl 和 Filament Group 在他们的预加载 CSS 研究中研究过的事情 - https://gist.github.com/scottjehl/87176715419617ae6994
你可能也会对 https://github.com/filamentgroup/enhance 感兴趣,它展示了他们异步加载 JavaScript 的工作流程,以一种合乎规范的方式。
我不认为这是“传入的 CSS”。分离样式和内容的目的是为了使开发人员的工作流程清晰。在这种情况下,如果我理解正确,开发人员不会看到任何内联 CSS。开发人员只需标记一些关键内容,剩下的就由自动化程序完成。
好文章,我们这里有有趣的讨论。我想补充几点(我写了文章中提到的工具之一)
是的,没有“页面可见区域”,但不要太纠结于此。我们只是想找到一个易于定义的断点,我们可以利用它来自动找出哪些是关键 CSS,哪些不是。尽管我理解想要手动指定什么是关键和非关键的想法,就像 Chris Coyier 所说 - 在我看来,这根本不可维护。你真的想在 CSS 或 HTML 发生任何更改后就必须重新修改所有 CSS 和 HTML 吗?或者你认为你的网站在其他 CSS 加载之前偶然闪烁一下未设置样式的内容是可以接受的?
每个用户和设备在初始加载(即“页面可见区域”)时都会显示不同的像素数量 - 但我们真的不需要太关注这一点。我们想要做的只是确保我们至少加载了加载期间屏幕上可见的所有内容,理想情况下尽可能少地加载其他内容。如果你真的强烈反对使用“页面可见区域”断点 - 只需在这些工具中的任何一个上设置一个非常大的断点(9999px),你仍然会获得裁剪掉当前页面未使用的所有 CSS 的好处。你的页面仍然会更快地开始渲染。
有人提到能够使用这些技术将他们的 CSS 削减一半(作为剩下的关键 CSS)。我现在已经通过 我的工具的在线版本 为大量的请求生成了关键路径 CSS,平均我看到的节省率接近 90%。显然,这取决于你的 CSS 有多 DRY 以及你的网站有多大,但对于任何大型网站来说,在 CSS 文件大小方面肯定有超过 50% 的节省空间。(关于同一点:无论你节省 50% 还是 90% - 如果你的网站的完整 CSS 小于约 14kb 压缩后,那么我不会真正考虑关键路径 CSS.. 只需内联你的完整 CSS,你将看到相同的性能提升)。
就这些技术让我们的工作有多难而言.. 我认为,由于我们网络社区的贡献,它并不一定那么难。如果你使用像 grunt 或 gulp 这样的任务运行器,只需在你构建中设置文章中提到的工具之一,让它自动为任何你想要的页面生成关键路径 CSS,在你模板语言中设置它来检查页面是否存在关键路径 CSS 文件 - 如果存在,就将其输出到 style 标签中!我编写我的工具是为了完全自动化此任务,因此你只需设置一次,以后就不用再管了。我打算写一篇关于你完成它所需要经历的每个步骤的教程,也许人们会觉得它有用。
关于我们目前如何向用户交付 CSS 以保持良好的性能.. 我也期待着 HTTP2,并让浏览器/服务器为我们处理一些事情。但当这种情况发生时,你可以肯定的是,我们会找到新的方法,从我们的网站中挤出一点点的性能提升。:)
尝试让我的 gravatar 启用。:)
有人提到在关键 CSS 中包含用户交互所需的 CSS.. 我强烈建议不要这样做。关键路径 CSS 的作用是让浏览器尽快开始渲染页面。在关键路径 CSS 中添加不是第一次渲染一部分的内容是.. 适得其反的。专注于一般的页面加载优化,这样你的完整 CSS(以及可能需要的 JS)就可以尽快加载。
我甚至会说,像图标字体这样东西 ideally shouldn't be part of the critical path css.. 如果你想更进一步,在你将 CSS 传递给像 Penthouse 这样的工具之前,先从你的 CSS 中剔除任何这样的规则,以获得更好的性能。我正在考虑让你能够传递一个要从关键路径 CSS 中排除的选择器“黑名单”…
我认为你指的是我。我指的是相反的想法:关键 CSS 应该**排除**用户交互 CSS。这可能是最安全的 CSS 排除方法,因为它不依赖于任意的视窗高度,而是依赖于人们不会对页面进行闪电般的快速交互。
如果有一些 Node(或其他)魔法可以提取带有
!critical
声明的属性,就像!important
一样,那将是多么神奇啊!那将是非常厉害的。
这是一种非常不好的做法,也是 Google 给出的更糟糕的建议。我们发现一个客户以不同的方式提供他的外部样式表,并实现了相同的效果。这违反了所有干净 HTML 的原则,是开发和可访问性的噩梦。
找到更好的方法,或者不要推荐任何方法。内联 CSS 违反了 CSS 的所有设计初衷。
它是在 HTML 文档中内联的,在一个 style 标签中,而不是在各个元素上。仍然与内容分离。
我经常想知道,当我订阅了这个网站上的帖子时,我经常会看到一些回复,这些回复本该直接回复其他人,而它们却被发布成了一个全新的回复。然后我会收到一封电子邮件通知我一些我想回复的内容,而我在帖子添加几分钟后就看不到那个评论。你可能要看看这个,Chris… 因为我现在开始理解为什么回复可能看起来没有正确地进行线程化了。
无论如何,我只想说… 对于一些读者来说,了解嵌入式样式和内联样式的区别可能会有所帮助。它们之间是有区别的。
我也认为这是胡说八道。如果你想成为一个反对者,要么提供一些数据和事实来支持你的观点,要么在你的博客上发表你的意见。
为什么人们坚持说“干净 HTML 的原则”我不理解。有时,为了实现其他目标,规则必须被打破。如果你遵循严格的规则生活,那么你可能和机器人没什么区别。人类会评估情况,可以根据具体情况灵活地调整规则。
试图找到我的评论和对它的评论。
你想要 CSS 规范和它的工作原理方面的哪些数据?继承是 CSS 的基础,而这种方法破坏了它。除了某些 CMS 之外,没有很好的理由来打破它,而这仅仅是因为你没有时间去纠正它。
至于我 - 我从 CSS 诞生之初就开始使用它,并且从 1998 年之前就开始手写 HTML 代码。我从 2004 年开始编写可访问性代码,并且从 2005 年开始从事 SEO 工作。
如果你认为内联 CSS 还可以,这是一个好主意。我不这么认为,所以这种类型的帖子只会造成更多代码噩梦,我会告诉人们删除它 - 特别是因为你可以在不这样做的情况下满足页面速度建议。
你只有在不知道怎么做或没有其他选择的情况下才会用 McGuyver 的方法来构建网站。你有其他选择,所以不需要 McGuyvering。
PS 告诉别人他们的想法很糟糕并不算恶意。但令人遗憾的是,这似乎是一个只有思想一致的人才能参与的博客。
好文章。令我惊讶的是,这里没有人提到,为关键 CSS 指定的任意屏幕尺寸会导致 FOUC(未设置样式的 CSS!)。当我尝试在我的网站上使用 loadCSS 时,24 英寸显示器底部五分之一的布局出现了问题。我们知道发生了什么,但普通用户可能会感到困惑,为什么网站没有正常加载。尝试刷新等等。
还有其他人遇到过这个问题吗?你们在 PC 监视器尺寸上都能获得一个有样式的视窗吗?
Nick,这就是生成关键 CSS 的“折叠”问题 - 找到要包含多少 CSS 的最佳点。我知道,即使是我的工具默认情况下也不会包含足够的 CSS 来正确绘制 24 英寸显示器的高度 - 但你可以将你自己的(更大的)尺寸传递给该工具,以生成更具包容性的关键 CSS。
理论上,如果你知道服务器上的用户视窗尺寸,那么你可以创建和提供更多特定于尺寸的关键 CSS(小、中、大)。
嗨,Nick。确实,需要一些尝试和错误才能确定什么对网站上的所有页面最有效,正如 Jonas 所说,针对更大的视窗和更小的视窗进行测试将有助于解决这个问题。
注意那些似乎不知道的人。你使用 head 技术(代码与文本比例)会导致 SEO 问题,如果不小心,你还会破坏 CSS 继承。此外,你还会创建一个开发噩梦(因为你必须在每个页面中查找代码),并且无障碍用户无法添加样式表(因为他们通常这样做),因为浏览器无法在你的内联样式之上插入继承的样式。这会造成比解决的问题更多的问题,而这些问题又可以不用它来解决。
因为这种误解会导致比帮助更多的问题,所以我把这篇文章也埋了。
这篇文章不是建议使用内联样式。它建议将某些样式标记为关键,并将它们移动到 head 中的样式块。关于 CSS 没有任何东西会坏掉。
这种模式很难与以下内容一起实现
响应式/基于媒体查询的网页
Web Components
目前常用的构建工具
像 Font-Face 和/或主 logo 这样的网络请求中的异步 CSS,鼓励使用内联 data:url,例如,当字体被认为是关键时。
事实上,spdy 或更新的网络协议应该解决并行导入,所以没有理由将内容分成块,因为所有被分割的内容都可以通过一个请求下载。
新的 HTML 链接导入
为旧式脚本添加的 JS 运行时样式
我认为,总体而言,等待更长的时间以获得完整的体验,而不是浪费时间进行子分割,对每个人来说都是一个胜利,100 毫秒的额外时间在现实世界中算不了什么,不要对这些技术太执着,总有一些国家的手机会花 10 秒钟才能看到任何东西 :P
Andrea,
虽然这项特定任务在将来会更容易,但这并不意味着我们现在不应该尽力而为。这样做带来的差异不是 100 毫秒,而更接近 1 秒,具体取决于你与什么进行比较,以及你的 CSS 大小。而这只是有线连接的桌面上的 1 秒。
在移动设备上,益处更大,因为 HTTP 请求更昂贵。如果你可以设法从你的 HEAD 中删除所有 HTTP 请求,并将你的关键 CSS 放在初始拥塞窗口内(完整 HTML 大小 < ~14.6kb),那么你很可能节省了你的渲染开始时间的几秒钟。
为什么对其他国家使用手机的人这么缺乏同理心?如果他们的连接不好,那么糟糕的性能会对他们造成最大的影响。如果你的网站加载时间更短,也许他们会考虑开始使用它。;)
–
关于你的列表
* 媒体查询、font-face、data-urls... - 所有这些事情都是自动处理的,至少在我的关键路径 CSS 生成器中是这样的。如果它在 CSS 中,并且在页面上“在折叠之上”使用,那么它将成为关键 CSS 的一部分。
* 至于难以与当前构建工具一起实现 - 你在这里指的是什么?使用 Grunt、Node、Gulp 或你自己的任务运行器,生成关键 CSS 应该很容易.. 你是在谈论自动设置将关键 CSS 放入你的 HTML 中吗?
在有线连接的桌面上,相差整整一秒?这很多,绝对值得优化带来的麻烦。
你认为那里的总 CSS 大小是多少?
Mike
这取决于你的比较。HTTP 请求是你可以为渲染开始时间获得的最大节省部分 - 如果你从在你的 head 中拥有任何阻塞的 >link< 样式表,到只内联任何合理大小的(>~20kb)关键 CSS,你应该看到至少大约 1 秒的节省(如果你的 HTTP 请求很大或速度很慢,则节省更多)。请注意,这要求你不在你的 HEAD 中留下任何其他阻塞的资产,例如 JavaScript,否则它们仍然会成为瓶颈(你将看不到任何节省)。
第二个主要节省
断点
是将内联 CSS 的大小缩减到足以让完整 HTML 请求(包括你的内联 CSS)适应初始拥塞窗口。因此,如果你将内联更大(完整)CSS 与内联足够小的关键 CSS 进行比较(以实现完整 HTML <~14.6kb 压缩),那么你会再次看到巨大的节省,尤其是在移动设备上(正如文章所解释的那样)。我没有关于这种比较的确切数字,但这绝对值得尝试。最后,如果你只是比较缩减内联 CSS 的大小,但没有突破上面提到的两个障碍之一.. 那么节省只包括更小的 HTML 请求的下载时间更少,以及 CSS 文件的解析和渲染时间更快 - 因为它将具有更少的规则。我尝试过获取一些关于这方面的数字,但我发现它变化很大,因为它在很大程度上取决于响应和下载时间 - 服务器端的东西。我只建议不要在你的内联 CSS 中追求字节,除非你能实现上面提到的两点之一。如果没有,专注于其他事情,例如压缩图像,或优化你的 JavaScript。
谢谢 Jonas,这真的很清楚,有助于将这些想法融入到透视中。
我现在很想知道如何使用这些想法并比较结果。:-)
感谢这些很棒的技巧。我一直被 Google 页面速度分析困扰着,需要修复这些类型的错误。
好文章。
一个语法注释
“如果你的部分不适合这种结构…”
your,而不是 you’re。
HeadJS 和正确实现的按需加载。故事的结尾。
cu, w0lf。
ps: 当然,像 WP 提供的资产排队系统也有很大的帮助;)
我不认为,在构建大型高性能网站时,将模块/部分划分为关键和非关键部分是一种可行的办法。在大多数情况下,问题在于,你为一个网站开发了大量的模块和组件,而所有这些组件都可以在任何模板上使用。因此,即使你考虑了关键和非关键,你最终也会得到 30kb+ 的关键 CSS。
最好是简单地将你的 CSS 和 JS 分成一个基础文件,一方面包括主布局,包括网格系统、页眉和导航以及所有模板布局,另一方面是很多小的附加样式表和 js 文件(每个组件都可以有一个或多个样式表/js 文件)。然后,这些组件可以在需要时加载。使用这种技术,你仍然最终会拥有更少的阻塞 CSS 和更少的未使用的 CSS,但这对开发者来说友好得多。
缺点是,你最终可能会对 CSS 有很多 HTTP 请求,这很容易超过下载更少字节带来的节省。
这可以通过一个巧妙的打包系统来缓解(我认为 Facebook 就是这么做的)。当然,这又增加了复杂性。在某些时候,你需要决定复杂性是否值得。对于 Facebook 或 Amazon,几乎可以肯定;对于小型企业网站,几乎可以肯定不值得。
最有效的方法取决于网站。如果网站在所有(或大多数)页面中都使用类似的设计,那么通常最好将 CSS 保留在一个文件(或少量文件)中。如果网站有非常不同的设计 - 例如,像雅虎这样的“门户”网站 - 那么最好将 CSS 分割成模块。
这些内容中的大部分在很久以前(在网络时间里)就被 Steve Souders 等人讨论过。这里唯一的新内容是这些工具的自动化(或半自动化),它们可以检查你的页面。
我完全理解您想要的益处,但我不确定在大多数情况下它是否实用。如果您的核心样式(normalize、base、typography、navigation 等)都为您的模块和辅助 CSS 设置了基础——这意味着后者在呈现方面至少部分依赖于前者,那么将这些部分从核心 CSS 中提取出来以用于关键路径中的模块/元素真的值得吗?我会尝试一下,但大多数中小型项目可能看不到足够的节省来证明花费的时间是合理的。在很多方面,它确实感觉像是倒退了一步,远离了网页标准您要链接的文本在这里…。Zeldman 之类的人对这个想法有什么看法,如果有的话?
这会如何影响浏览器缓存?
如果我们使用这种技术,后续页面的权重会随着我们加载额外的 CSS 字节而增加吗?这些字节原本会在第一页视图加载,然后被缓存。
非常好的观点。页面速度洞察只是假设单页加载,没有任何缓存。随着时间的推移,这些额外的字节会累积起来。在一个大型网站上,这意味着更大的带宽账单。
我想知道使用 cookie 是否会有帮助?基本上,在初始页面加载后,设置一个 cookie。在您的网站模板中,如果模板看到这个 cookie,那么它们已经从之前的页面获得了 CSS(假设内联样式也是较大 CSS 文件的一部分)。您需要一种方法来使“cookie”失效,假设您的 CSS 发生了变化(通常通过文件名来完成)。
确实,使用这种技术,您网站上每个页面 HTML 和 CSS 的总字节数会更大,但您可以做更多事情,并通过优化甚至删除我们都喜欢的那些华丽的 2x 视网膜图像来弥补这一点 ;)
Dave,您可能想看看 https://github.com/filamentgroup/enhance,它为后续请求提供了一种方法。
@ Ben:感谢链接,看起来很有用。有什么是 Filament 没有参与的吗?!
任何考虑这样做的人最好先确保其他基础都到位:合并和压缩 CSS/JS、优化和调整图像大小、CDN 等。