这篇文章的目的是研究前端开发人员如何建立快速的登陆页面,这是由Core Web Vitals判断的。
这些网页性能指标是谷歌搜索的一个新的排名信号,也是数字营销人员和搜索引擎优化专家所关注的。自从谷歌在2000年5月宣布这些指标以来,企业主要求前端开发人员修复缓慢的网页并建立更快的网页。
现在,Core Web Vitals已经开始推出,我去寻找最佳的前端性能模式。
什么是Core Web Vitals?
Core Web Vitals的主题包括三个以用户为中心的网页性能指标,这些指标来自真实的Chrome用户数据(CrUX)。这些分数在28天的滚动期内被汇总到第75个百分点。这三个指标是:。
- 最大内容绘画(LCP):网站在屏幕上显示最大元素所需的时间。它应该在2.5秒内被用户看到
- 首次输入延迟(FID):这是对网页响应用户输入所需时间的衡量,应该在100毫秒之内。
- 累积布局偏移(CLS):这是网页元素和布局在页面加载时的意外偏移,所以最好避免在加载过程中偏移页面的布局
对照最慢的连接和设备的用户来衡量你的网页是很关键的。
因此,我将我的连接节流到快速3G,并将我的CPU速度降低6倍。只有这样,我才能够浮现出谷歌搜索控制台报告的问题。
提高你的核心网络生命力得分
解决页面速度问题的秘诀是对已经拥有良好Vitals的页面进行反向工程。首先,我需要一个大多数网站都有的页面类型,因此,为了这篇文章的目的,我选择测量无处不在的定价页面,因为它们在各网站的视觉上是相似的,通常包括一个突出的行动呼吁。
然后,我用Lighthouse测试了114个移动页面,并将它们与Core Web Vitals进行了比较。这样一来,我就剩下25个快速登陆页面需要分析了。
这些网站的技术范围从Next.js到WordPress再到Ruby on Rails,有些甚至使用了jQuery。无论你(被迫)使用什么堆栈,总有办法提高你的Core Web Vital分数。
由于这些模式是利用谷歌浏览器用户体验报告(CrUX)中的数据从现有网页中逆向推导出来的,我相信如果你遵循这些模式,你将建立一个快速的网页,甚至修复一个缓慢的网页。
要想自己调查这些模式,我建议加载页面,然后查看源代码。
将后端时间保持在600ms以下
最快的10个网站的服务器响应时间从75ms到380ms不等,中位数为110ms。经验之谈?该领域的第75个百分点可能需要持续低于600ms。
| 域名 | 网址 | TTFB |
|---|---|---|
| basecamp.com | basecamp.com/pricing | 59 |
| 禾丰网 | www.getharvest.com/pricing | 322 |
| 海报ywall.com | www.postermywall.com/index.php/p… | 94 |
| loom.com | www.loom.com/pricing | 380 |
| 梦之城_梦之城娱乐_梦之城国际娱乐_梦之城国际娱乐平台 | evernote.com/compare-pla… | 255 |
| Trello.com | trello.com/pricing | 107 |
| loom.com | www.loom.com/pricing | 123 |
| shopify.com | www.shopify.com/pricing | 202 |
| agilecrm.com | www.agilecrm.com/pricing | 118 |
| 新锐网 | newrelic.com/pricing | 76 |
| 萌芽社会.com | sproutsocial.com/trial/ | 129 |
计算性能预算
在查看代码之前,我建议对请求的文件进行清点,并按内容类型进行细分。然后将你的页面与一个快速页面进行比较。这就是所谓的性能预算。
我创建我的预算是通过分解每个类型的文件,在最大的内容画(LCP)之前加载。例如,Shopify加载了超过100个文件,但构建页面时,它在最大的contentful paint之前加载了17个文件。
在LCP之前,快速页面一般会加载。
- 总文件数少于35个
- 四个或更少的第三方脚本
- 没有媒体文件
- 只有两个样式表
- 不超过10个脚本
- 最多四个自定义字体
- 多达15张图片
在LCP之前预先连接到要求的域
正确构建的页面首先要找到这35个文件所使用的所有域,然后使用preconnect 资源提示。Shopify使用这种模式来预连接到关键域。
<head>
<link rel="preconnect" href="https://cdn.shopify.com" />
<link rel="preconnect" href="https://monorail-edge.shopifysvc.com" />
<link rel="preconnect" href="https://sessions.bugsnag.com" />
<link rel="preconnect" href="https://www.google-analytics.com" />
<link rel="preconnect" href="https://www.googletagmanager.com" />
<link rel="preconnect" href="https://bat.bing.com" />
<link rel="preconnect" href="https://www.facebook.com" />
<link rel="preconnect" href="https://connect.facebook.net" />
<link rel="preconnect" href="https://tags.tiqcdn.com" />
<link rel="preconnect" href="https://lux.speedcurve.com" />
</head>
这允许浏览器在文件被请求之前打开连接。
预加载和托管字体文件
大多数网站都依赖自定义字体,并使用font-display: swap ,以便在下载自定义字体之前文本是可见的。PosterMyWall是一个模式的例子,它的字体是预先加载和自我托管的。这是加载和呈现自定义字体的最快方式。
<head>
<link rel="preload"
href="https://www.postermywall.com/assets/fonts/NunitoSans/NunitoSans-R
egular.woff2"
as="font" type="font/woff2" crossorigin="anonymous">
<!-- Suggested improvement →
<link rel="preload" as="style"
href="https://pro.fontawesome.com/releases/v5.13.0/css/all.css"
onload=”this.rel='stylesheet'">
</head>
如果你需要使用谷歌字体,你应该寻找使用Mario Ranftl的google-web-fonts-helper。
避免使用图标字体
避免使用图标字体的主要原因是,它们会产生一个请求链。这意味着根文档必须加载一个样式表,而样式表在渲染图标之前又会加载图标字体文件。但是一个简单的带有高度和宽度属性的图像没有任何依赖性。
如果你需要使用图标字体,Sproutsocial在预加载字体和异步加载字体时,概述了一个有用的模式。我另外建议也要预装图标字体文件。
<head>
<link rel="preload" as="style"
href="https://pro.fontawesome.com/releases/v5.13.0/css/all.css"
onload=”this.rel='stylesheet'">
<!-- My recommendation -->
<link rel="preload"
href="https://pro.fontawesome.com/releases/v5.13.0/webfonts/fa-so lid-900.woff2"
as="font" type="font/woff2"
crossorigin="anonymous">
</head>
我也看到了在内联中添加@fontface 规则的好处,这样可以消除对渲染的阻碍all.css 。
不需要内联关键的CSS样式
我惊讶地发现,许多网站都没有内联样式。相反,他们创建了一些小的CSS包,以便在<head> 中加载。例如,Loom预装的外部样式表总共约15KB。
也就是说,亚马逊AWS加载的是一个74KB的阻断渲染的CSS文件。所以,不要因为Lighthouse或某个帖子(比如这个)的推荐而使用一个模式。
<head>
<link rel="preload" href="/_next/static/css/4971ebe5c5a60f5f989b.css"
as="style" />
<link rel="stylesheet" href="/_next/static/css/4971ebe5c5a60f5f989b.css"/>
<link rel="preload" href="/_next/static/css/33a02aaca547371a75e0.css"
as="style" />
<link rel="stylesheet" href="/_next/static/css/33a02aaca547371a75e0.css"/>
</head>
加载小的JavaScript包
我的预算建议在最大的contentful paint之前不超过10个脚本。这不允许加载10个大规模的文件,但最好的网站在页面底部智能地应用async 或defer 属性加载小脚本(2到35KB)。
有几个网站使用Next.js,它提供了在交互式运输JavaScript内联之前和之后加载脚本的能力,以及懒惰加载脚本的能力(对第三方供应商来说非常好)。脚本也是预加载的。
如果你在预装脚本时有不同的技术栈,要注意资源排序。
对小图片使用内联SVG,其余的懒惰加载
如果你有可以成为相对较小的SVG的图片,请内联它们。Trello将所有在折叠上方的SVG图片内联,然后懒惰地加载那些在屏幕外或隐藏的图片。
我也曾对折叠上方的图片使用过loading=eager 。像Trello这样的网站使用本地的loading=lazy 属性,但也观察到了JavaScript的解决方案。
<body>
<svg
height="16"
viewBox="0 0 16 16"
width="16"
<path>...</path>
</svg>
<!-- Native -->
<img
src="//images.ctfassets.net/TREL-210_Trello_Access_Spot_Illo.svg"
alt="Atlassian Access"
width="271"
height="190"
loading="lazy"
class="Picture__Image-sc" />
<!-- Script -->
<img
src="https://www.postermywall.com/assets/.../placeholder-image.png”
data-src="https://d1csarkz8obe9u.cloudfront.net/.../green-restaurant.jpg"
class="pmw-lazy" alt="Blog post" />
</body>
使用<picture> 元素来显示一个大的英雄图像
所分析的页面中没有一个包含英雄图像组件,所以我搜索并找到了Trulia,它采用了一种新的模式。首先,他们设置了一个PerformanceMark,这在我看来是一种高度的故意。
冒着过度简化的风险,我观察到,对于大型的英雄图像,开发人员使用了包含19个<source> 元素的<picture> 元素,涵盖了所有类型的使用情况。不仅图像的大小和压缩正确地适用于桌面和移动设备,而且他们利用了<picture> 的艺术指导能力。这也告诉我,用户体验团队是这个解决方案的一部分。
<picture class="Picture__PictureContainer-sc-1exw3ow-1 gteZiU">
<source
srcSet="https://www.trulia.com/images/app-shopping/homePage/extraLarge.jpg"
media="(min-width:993px)" />
<source
srcSet="https://www.trulia.com/images/app-shopping/homePage/medium.jpg"
media="(min-width:768px)" />
<source
srcSet="https://www.trulia.com/images/app-shopping/homePage/medium.jpg"
media="(min-width:570px)" />
<source
srcSet="https://www.trulia.com/images/app-shopping/homePage/small.jpg"
media="(min-width:376px)" />
<source
srcSet="https://www.trulia.com/images/app-shopping/homePage/small.jpg"
media="(min-width:0px)" />
<img
loading="auto"
decoding="auto"
id="homepage-banner-image"
style="background:url(src="data:image/image/png;base64,iVBOR==");
background-size:cover"
width="100%"
height="100%"
src="https://www.trulia.com/images/app-shopping/homePage/extraLarge.jpg"
alt=""
class="Picture__Image-sc-1exw3ow-0 tzLdz" />
</picture>
而且,为了模拟背景图片,他们利用position 属性,将几个<div> 元素分层,以完成该组件。其结果是惊人的。
在桌面上,大的背景图片在600ms内出现,LCP在900ms内发生。然后在缓慢的移动设备上,它在1.8s出现,并在2.2s前完成。
图像绘制的秘密是巧妙的。
<img> 元素有一个内联样式设置,一个基数为64的编码,以及一个10px by 5px的JPG作为背景图片,高度和宽度设置为100%。这就是为什么它的绘画速度如此之快,并有一个很好的效果,使图像从模糊到清晰。哇。
当<readyState> ,加载第三方脚本是互动的
管理第三方供应商是一个挑战,特别是当预算建议在LCP之前只加载四个脚本时。尽管这样,该企业仍然可以使用第三方供应商,因为所分析的页面平均要求完全加载103个第三方文件。因此,我着手看看最好的网页是如何处理供应商的脚本的。
最好的模式是在readyState 之前加载最多四个脚本(即标签管理器、AB测试、RUM),然后在document.readyState 之后加载剩余的complete 。
<head>
<link rel="preconnect" href="https://assets.adobedtm.com" />
</head>
<body>
<!-- Bottom of HTML →
<script src="https://assets.adobedtm.com/launch-EN.min.js" async></script>
<! -- Self-host -->
<script src="https://cdn.shopify.com/speedcurve-lux/js/lux.js?id=64441087" async defer crossorigin="anonymous"></script>
</body>
如果你采用了一个标签管理器,瀑布应该是可以预期的。它在DOMContentLoaded 之前加载关键的第三方,包括你的标签管理器脚本。然后,将浏览器的事件触发器设置为Window Loaded,用于你所有剩余的脚本。
这描述了最好的模式。然而,你的情况可能需要不那么积极的东西。启示是要控制脚本的加载时间,不仅仅是对供应商,而是对所有的脚本,以优化瀑布流。
用数据驱动的模式来改善核心网络生命力
我确信在解决LCP问题时我遗漏了一些东西,但这些案例研究强调了为什么核心网络生命力(首次输入延迟)并不能带来更好的JavaScript模式。
此外,我不会期望这些高质量的网站不能通过累积布局转移。但是,我想如果我分析的是广告支持的文章而不是定价页面_,_我会发现更多的CSS模式。
这种分析并不令人惊讶。所有这些模式都是有据可查的,除了使用图片元素来制作大的英雄图像之外。
但如果你要选择一个解决方案,我建议使用这些模式,这些模式是基于案例研究的,而不是Lighthouse列出的建议。