您是否知道如果网页加载时间超过 4 秒,25%的用户会放弃等待呢?失去如此多的流量是网站所有者无法承受的风险。
衡量网站效率
优化您的网站的第一步是找出确切需要优化的地方。尽管您可以使用许多工具来执行此操作,但是您仅需要了解以下两个工具:
如今,每种现代浏览器都有自己的“开发人员工具”集,它们并没有本质上的区别,随便你使用内置于 Firefox 和 Safari 的工具,你喜欢就好。话虽这么说,但是 Google 的 Chrome 浏览器的“开发人员工具”高于平均水平。结合我们必须就本教程达成共识的事实,我们将在本指南中使用 Chrome Tools。
首先,通过菜单(“视图>开发人员>开发人员工具”)或相应的键盘快捷方式(在 Mac 上为 Cmd + Opt + I 或在 Windows 上为 Ctrl + Shift + I)打开窗格。确保激活“网络”选项卡以查看与性能相关的数据,并激活“禁用缓存”复选框。这样可以确保我们的页面第一项访问者都拥有相同的体验。
现在,要真正开始记录数据,只需重新加载页面。这样做之后,您会立即发现窗格中充满了条形和数字。
窗口下部的表格列出了与此页面相关的所有资源。默认情况下…资源按请求顺序排序。一个有用的替代方法是按它们的大小排序(通过单击“大小”列标题)。这样,您可以识别出可能会最大程度降低页面速度的大块数据。
显示了所有类型的资源。例如,如果某个时候只想查看图像,则可以使用过滤器栏中的按钮(当前已选择“全部”按钮)来缩小列表范围。不必太担心不同的条形和它们的颜色。为了提高网页的总体性能,查看窗口底部的总体统计信息会更加有趣。
“开发工具”窗口的页脚包含我们页面性能指标的有趣摘要。详细地,它为我们提供了以下主题的信息(从左到右):
在本指南中,我们应该努力改善这些数字,以便为访问者提供更快的体验。如果您想深入阅读有关开发工具的手册,则可以跳至 Google Developer Tools 自己的文档。
Google PageSpeed
另一个有用的工具是 Google PageSpeed 分析器:
当您使用 URL 提交它时,它将解析该页面以查找常见的性能问题。这是一个很好的工具,可以帮助您了解页面的“现状”。此外,它直接提供了一些简短的改进提示。
简而言之,获取提示和技术概述。即使您自己在某个领域优化很出色,我仍然强烈建议您查看此处介绍的所有技术,您将会很高兴知道如何将更优秀的性能提升到您的页面中。
优化图像
平均而言,图像占网页重量的 60% 以上。
对于要下载的最大字节,图像通常是站点加载时间的最大障碍。但是,另一方面,这也使图像具有优化的巨大潜力。
在本章中,我们将研究处理图像的正确方法,以使我们的网站更快。
摆脱图像
您页面上包含的每个图像都会带来巨大的性能成本:必须将其下载到用户的计算机上。因此,您可以使用的最佳图像实际上就是没有图像!
如果可能,请消除图像,并不是每一个图像资源都具有指导意义,言语无法直观表达的图像资源才有存在的必要。
CSS Drawing
由于现在在所有现代浏览器中都可以使用 CSS3,因此彻底改变了游戏规则:只需使用几行 CSS,就可以轻松完成许多需要使用图像的操作。
想想阴影,圆角,渐变,透明胶片,气泡甚至是动画-突然之间,这些使没有图像成为可能。
网络字体
在图像内渲染文本通常是一个坏主意:图像使用不必要的带宽,无法选择或搜索文本,并且无法像“真实”文本那样很好地适应不同的屏幕尺寸和像素密度。
所有这些都可以通过使用 Web 字体来避免。你能够重复使用自定义字体设计,并且没有影响性能,也没有丢失语义。
正确选择图像格式
一旦确定必须需要某个图像(当您无法使用 CSS 或 Web 字体替换它)时,就该为它找到最佳格式了。不幸的是,在图像格式方面,没有“固定”的解决方案:您必须仔细查看每张图像,然后找到最适合的图像。
- 图像是否包含几何形状?
当图像场景由直线,圆和其他路径组成时,SVG 格式可能是理想的选择。由于它是矢量格式,因此它使用几何形状来描述图像。这通常使图标和徽标之类的东西成为 SVG 的理想选择。
当图像的特征适合 SVG 时,不仅会导致文件变小:可以缩放 SVG 而不损失质量,从而使它们完全独立于屏幕分辨率和像素密度。
- 图片是照片还是屏幕截图?
当图像包含许多细节和不规则性时(通常像照片一样),JPEG 格式可能是正确的选择。尽管 JPEG 使用有损算法来压缩文件,但是图像中许多颜色和许多细节的组合通常使它成为唯一可行的选择。
保存 JPEG 时,请稍稍调整质量设置,您通常会在文件大小和质量之间找到一个很好的折衷方案。
- 您需要透明度和/或最高质量吗?
当您需要图像透明时,可以快速排除 JPEG 格式。相反,在这种情况下,您很可能会使用 PNG 格式。PNG 的另一个好处是它仅使用无损压缩算法。这意味着当您需要最大质量的图像并且不能接受丢失任何精细细节时,它是理想的选择。
另一方面,所有这些优点(当然)都是要付出代价的:PNG 产生相当大的文件大小,因此仅在其他选项不起作用时才应使用。
最后,请记住,PNG 有两种风格:使用较小的调色板(<= 256色)时使用 PNG-8;仅当图像中需要大量颜色时才使用 PNG-24。
特例:动画
如今,可以使用几种不同的方法将动画合并到图像中:
该 GIF 图像格式是一种很常见的,建立的方式。有许多工具可以帮助您创建动画 GIF,而对浏览器的支持非常出色。
该 SVG 格式还提供了动画功能 - 虽然可能比较费力创建和当前的浏览器为 GIF 没有得到很好的支持。
考虑到 CSS3,在动画方面,很多事情都是可能的。尽管可能性绝对是有限的,但是 CSS3 可以提供非常有效的动画替代方法。
当然,除了此处列出的方法外,还有许多其他方法。对它们的研究将远远超出本指南及其重点的范围:从性能优化的角度来看,GIF,SVG 和 CSS3 可能是实现动画的最有效方法。
优化技术
以下是有关图像优化的最常见可能性的概述:
- 您的第一步应该是为每个图像选择最佳的文件格式。
- 如果选择有损格式(如 JPEG),则在保存文件时,可以使用图像编辑器的“质量”设置进行播放。您必须决定要舍弃多少视觉质量(以模糊,伪影等形式),以便获得较小的文件大小。
JPEG 格式还提供“渐进式”模式。虽然这不会减小文件的大小,但可以提高访问者的感知性能,因为浏览器可以更快地开始显示它。
- 如果选择 PNG 或 GIF 之类的格式,则可能需要减少图像中的颜色数量。如果您愿意接受视觉效果,则缩小到较小的调色板可以大大缩小文件的大小。
- 如果选择 SVG 格式,请确保通过 SVGO 之类的工具运行该格式。您可以通过减少内容并删除不必要的元数据(例如注释和图层信息)来节省一些字节。
- 如果选择栅格格式(例如 GIF,PNG,JPEG),则通常需要进行其他优化。尽管 Photoshop 和其他图像编辑器会尽力保持较小的文件大小,但专用工具通常可以挤出另外几个字节(或千字节)。
在最近几年中,出现了许多图像优化工具。我们整理了一些受欢迎的清单,以帮助您入门:
自动化/命令行
线上工具
桌面工具
加载正确的图像
在当今的网络中,大量不同的设备给我们带来了挑战:不同的屏幕尺寸和像素密度使在任何设备上显示良好的页面成为一项艰巨的工作。您很可能会希望为普通 DPI 屏幕和高 DPI 屏幕提供单独的图像。而且您甚至有可能希望为更大或更小的屏幕尺寸提供单独的图像。
但是,故事并不仅限于创建各种替代图像。我们还需要确保我们巧妙地处理它们。如果不这样做,可能是因为我们在无法显示所有像素的设备上下载了一个巨大的,高 DPI 图像资产,从而导致带宽浪费和加载时间缓慢。
仅加载需要的图像
经验法则是,仅应该为当前焦点加载正确的图像。
例如,如果您的网站上有图片库,则应为那些小的缩略图预览和较大的原始图片创建单独的图像。
但是您可能会倾向于采用“懒惰”替代方案:为什么不总是只提供较大的原稿,而只是将较小的“宽度”和“高度”属性包括在内?尽管这样做可以避免创建单独的图像,但是这也意味着您将浪费大量的带宽:要显示概述页面,客户端必须下载大量的大图像 - 即使只有小的缩略图也是如此。实际上访客将永远被动等待,直到她看到概述为止。
使用响应式图像
像小图片库这样的情况很容易处理。响应式 Web 具有多种屏幕分辨率和尺寸,使得始终提供正确的图像变得有些困难。但是,已经出现了解决方案。
“srcset”属性
现在,大多数现代浏览器都支持 img 元素上的srcset
属性。它使您可以在单个 img 标签中定义图像资产的多种尺寸以及使用每种尺寸的条件。
让我们看一个非常简单的例子:
<img src="learn-mascot.png"
srcset="learn-mascot.png 1x,
learn-mascot@2x.png 2x">
在这里,我们在srcset
属性中提供了两个不同的图像文件(以逗号分隔)。除文件名外,我们还确定条件:第一个应在 1x 屏幕上使用,第二个应在 2x(高 DPI)屏幕上使用。然后,浏览器将根据设备的像素密度自行决定要使用的资产。
如果您不遗余力地想要提供更大尺寸的图像,则srcset
已准备就绪:
<img src="learn-mascot.png"
srcset="
learn-mascot@0.5.png 300w,
learn-mascot.png 600w,
learn-mascot@2.png 1200w,
learn-mascot@3.png 1800w"
sizes="
(max-width: 20em) 30vw,
(max-width: 30em) 60vw,
(max-width: 40em) 90vw">
在上面的示例中,我们提供了四个不同的图像文件,以更好地适应不同的情况。因此,我们添加了相应图像的大小,而不是在文件名后添加 “1x” 或 “2x” 。
除了此实际大小外,我们还应该让浏览器知道图像的布局大小 - 它将在屏幕上占据的空间。这就是sizes
属性的含义:例如,我们可以根据屏幕宽度为图像指定不同的显示尺寸。简单的媒体查询早已在响应式网页设计中广为人知,可用于这些声明。
有两个原因使srcset
成为您的快乐之选:
- 请注意,在这种情况下,我们不会告诉浏览器实际应使用哪个文件。浏览器将根据具体情况自行选择“正确”文件。我们只为它提供了一些备用文件,以及图像将占用的屏幕尺寸。
- 还要注意的是,我们不担心向后兼容:如果浏览器不支持
srcset
属性,它会简单地使用定义好的文件 SRC 作为备用。
如上所述,借助scrset
属性,浏览器可以自行选择显示哪个图像文件。如果您想自己接管并控制它,那么picture
元素很适合您。它指示浏览器根据自定义条件使用不同的图像文件。这使您可以在不同的情况下使用不同的图像。例如,大屏幕的宽幅全景图像和小屏幕上的全景图像完全不同(也许是裁剪后的版本,仅专注于大图像的细节)。有时将其称为“艺术指导”。
<picture>
<source media="(min-width: 900px)" srcset="mascot.png 1x, mascot@2x.png 2x">
<source media="(min-width: 400px)" srcset="mascot_small.png 1x, mascot_small@2x.png 2x">
<img src="mascot_medium.png" srcset="mascot_large.png 2x" id="mascot-image">
</picture>
如您所见,picture 只是一个包含多个 source 元素和一个 img 标签的容器。您可以使用 source 元素来建议在某些条件下应使用的图像的不同替代方案,即简单的媒体查询。然后,浏览器将使用提供匹配媒体条件的一个源图像。请注意,source 元素也可以具有srcset
属性。这使我们能够为设备的像素密度提供正确的图像。
对于不支持 picture 元素的浏览器,img 标记可作为备用。它也是您要应用的 CSS 样式目标(您不应在 CSS 中定义 picture 元素)。到目前为止,几乎所有现代浏览器都实现了srcset
属性。在某些情况下,可能不支持使用<picture>
元素。鉴于这些技术,我们已经能够使用包括 Picturefill 填充工具库。
尽管通常很容易,但传递响应式图像也可能成为一个复杂的话题。如果您想了解有关此主题的更多信息,请查看以下资源:
不要加载对于设备规格而言过大的图像(像素密度或屏幕尺寸),鼓励使用诸如“srcset”和“picture”之类的自适应图像技术在每种情况下提供最佳的可用图像。
减少 HTTP 请求
无论我们是在谈论 CSS,JavaScript 还是图像文件,您在页面上包含的每个资源都是有代价的。最明显的性能影响与文件的大小有关。构成其内容的所有字节都必须下载到访问者的计算机上。文件包含的字节越多,用户必须等待的时间就越长。
合并档案
页面中包含的每个资产都必须由浏览器请求。建立和管理这些 HTTP 连接需要时间。在大多数情况下不明显,但是当包含多个文件时,问题很快就会凸显出来。
更糟的是,浏览器在限制同时允许多少个请求方面存在限制。例如,如果您的页面包含30个资源,则访问者的浏览器将分批下载(通常在2到8之间)。这意味着即使单个文件的大小很小,也要花费相当长的时间才能下载所有文件。
因此,为了实现我们的网站性能良好的目标,我们必须确保尽可能减少 HTTP 请求。
Combining CSS and JavaScript
现代网站的 JavaScript 和 CSS 都由许多小部分组成:包括外部框架和库,并且您自己的代码也封装在模块化部分中。最后,您可能有10个或更多单独的 CSS 文件组成了网页的前端(JavaScript 也是如此)。
思考解决问题是高质量 Web 开发的基本要求。不必一定在 HTML 中分别包含和交付这些部分,取而代之的是,使用所谓的“预处理器”工具很有意义:除其他事项外,它们将所有必要的CSS or JavaScript 资源组合到一个 CSS or JavaScript 文件中。然后,浏览器只需打开一个 HTTP 请求即可下载一个资源,而不是多次。
如果您使用的是 Ruby on Rails 或 Django 之类的框架,那么这样的预处理器很可能已经成为工具箱的一部分。如果没有,请检查 CodeKit(Mac),Prepros(Mac,Win,Linux)等工具或适用于 Grunt 或 Gulp 的相应插件。
Combining Images in CSS Sprites
同样的原理也适用于图像:您可以将它们组合成一个所谓的“CSS Sprite”(CSS 精灵),而不是单独提供每个图像文件,它只是一个较大的图像文件,其中合并了多个图形。在同一个文件中包含少量图像之后,您就可以通过 CSS 作为背景引用该图像。正确设置宽度,高度和背景属性后,您将可以使用同一物理文件显示不同的图像。
串联 CSS 和 JavaScript 时,该技术具有与上述相同的优点:将许多资源合并到一个文件中意味着要下载的文件更少,意味着 HTTP 请求更少,从而最终提高了页面性能。但是,就像在很多事情上一样,您可以轻松地做到这一点:CSS Sprite 在将许多较小的图像组合到一个文件中时效果很好。这使其非常适合徽标,图标和其他较小的图像资产。相比之下,将几张大幅照片组合在一起将不会带来很多乐趣。实际上,最好将它们留在自己的单独文件中,因为压缩算法的效率不高,浏览器中的内存消耗将激增。
您不必手动执行此操作。以下是一些可帮助您创建 CSS Sprite 的工具:
避免重定向
如果您想要快速的网页,则将 HTTP 请求的数量保持在最低限度是一个重要的基本规则。使用 CSS 图像精灵以及合并 CSS 和 JavaScript 并不是减少 HTTP 请求的唯一方法:避免重定向同样重要。
这样做的原因就像其他任何请求一样,重定向会导致增加到服务器的往返时间。如果您不走运,还必须执行其他任务,例如 DNS 查找和 TCP 握手。
所有这些仅意味着一件事:您应该仔细检查加载页面是否涉及重定向。例如,应该为所有设备提供现代化的响应页面,而不是将移动访问者重定向到特殊的“m.bookcc.top”位置。
修复 404 错误
毫无疑问,404 错误并不讨喜:这意味着找不到请求的资源。当用户在浏览器的地址栏中输入一个 URL 并收到传说中的“找不到页面”消息时,这是最明显的尴尬。任何资源(例如图像,CSS 文件或 JavaScript)都可能丢失。删除或简单地重命名 CSS 文件太容易了,而忘了更新引用它的位置,新的 404 错误诞生了。
但是,为什么这是一个问题呢?请求资源,但找不到资源 - 故事结束,对不对?
因为请求资源涉及一个 HTTP 请求。而且您已经知道这些很昂贵。即使请求未返回任何数据,其连接开销也会稍微减慢页面加载速度。
尽管发现此类错误确实很容易,也很容易修复。使用浏览器的开发人员工具,您可以在“网络”流量中搜索返回 404 响应的资源。在 Chrome 开发工具中,您只需按响应“状态”进行排序即可立即查看任何错误的请求。
更快地传送文件
作为 Web 开发人员,您可能会认为请求资源是一件简单的事情:浏览器请求文件,然后服务器将其交付。但是,当我们查看HTTP 缓存时,有很多优化潜力可以挖掘,例如 HTML,CSS 或 Javascript 文件)。
在进入服务器获取资源的方式之前,浏览器会查看其自己的本地缓存:如果请求的资产先前已下载(在上次访问时或在网站的其他页面上),则往返于服务器可能没有必要。资产直接从本地浏览器缓存中返回 - 可以避免网络延迟和数据下载。对于访客(将立即获得资源)和对您(服务器无负担),这都是最佳方案。
为什么浏览器可能无法从其缓存中传递资产有很多可能性:最明显的是,当用户第一次访问该网站时;还有已经下载的资产不再被认为是“新鲜”的资产。在这种情况下,浏览器将不得不启动一个请求。
如果使用 CDN 或代理,它们可能会介入并响应请求(当然,仅当它们在其缓存中有资源时)。尽管这不如来自浏览器本地缓存的响应速度快,但它仍然比打扰我们的 Web 服务器交付资产要快得多。
如果不涉及 CDN 和代理,或者如果缓存规则要求使用 CDN 和代理,则要求我们的 Web 服务器提供资产。如果幸运的话,服务器仅可以响应“304 Not Modified”标头:我们必须往返于服务器 - 但是我们不必实际下载任何内容。
在所有其他情况下,只需从服务器请求资产,然后将其全部下载到用户的计算机即可。这意味着网络延迟,下载(可能很多)数据,流量成本上升…… 甚至更坏的情况发生。
要记住的重点是,我们有很多可行性方案防止这种最坏的情况发生。
让我们来谈谈可以优化的地方,和必须做的有效优化。
每当资源下载,实际文件本身只是一个交易的部分,还有 HTTP 头附带的文件,重要的元数据,特别是从高速缓存的内容。
提供所需的缓存指令是我们的工作。但是“理想”配置没有黄金法则 - 每个项目甚至可能每个文件都需要最适合用例的自己的缓存策略。
让我们详细了解两个最重要的指令。
缓存控制
顾名思义,该指令完全是关于控制的:您可以定义谁可以缓存文件多长时间以及在什么条件下进行缓存。
由谁:「公共和私人」
将 HTTP 响应标记为“私有”允许仅由浏览器缓存它,而不由代理或CDN之类的任何中间缓存来缓存。对于高度个人化的数据(例如在社交网络应用程序中),这是完美的选择。另一方面,将其标记为可公开缓存可允许“任何人”(浏览器,代理,CDN)在“任何”情况下(即使涉及 HTTP 身份验证)也对其进行缓存。由于其他指令(例如“max-age”(请参见下文))隐式设置了可缓存性,因此很少需要使用 public 关键字。
持续多长时间:「最大年龄」
cache-control: max-age = 86400
这个指令非常简单,它确定响应可以在随后的请求中重用多少秒。例如,通过将其设置为 86400(60秒x 60分钟x 24小时),浏览器可以在发出初始请求后的1天内使用缓存的资源。
在什么条件下:「无缓存 和 无存储」
「no-cache」 指令有点让人误解:用这种方式标记的响应很可能会被缓存;但是浏览器必须要求服务器确保在此期间没有新版本的资源出现。这意味着肯定会发生到服务器的往返 - 但如果资源仍然“新鲜”,则不会下载任何数据。另一方面,使用“no-store”指令,禁止所有缓存:浏览器每次都必须从服务器请求并下载文件。
您当然可以结合这些指令使用,例如:
cache-control: private, max-age=31536000
ETag
我们已经多次提到资源的“新鲜度”:如果资源没有更改,那么如果我们已经根据先前的请求下载了资源,则没有理由再次下载它。但是,我们如何知道资源是否已更改?“ETag”指令可以帮助我们解决这个问题。
服务器交付资源时,它可以包含“ETag”验证令牌 - 本质上是内容的哈希。如果文件的内容更改,则此验证令牌也将更改。等式的另一部分是浏览器:如果它在上一个请求中收到文件,则它会自动发送文件的 ETag。因此,服务器可以查看客户端是否具有文件的最新“版本”,然后可以返回简单的“304 Not Modified”标头。
在这种情况下,发生了到服务器的往返,但是我们不必下载任何实际数据。
配置服务器
浏览器很容易使所有这些“ETag”和“Cache-Control”指令生效。在发出 HTTP 响应时,我们“仅”必须确保我们的服务器包含适当的标头。
当然,每个 Web 服务器的实际配置值都不同。幸运的是,几名天才为所有主要服务器编写了一套最佳实践配置:github.com/h5bp/server-configs
此外,这种配置的详细信息取决于项目的类型:不同方案中的不同文件可能需要不同的缓存策略。但是在大多数情况下,它提供了一种非常简单而有效的缓存策略。
URLs 标识符
在实施缓存时,请记住,浏览器通过其 URL 识别资源。尤其是相反的情况对我们很重要:如果资源获得新的 URL,浏览器会认为它是不同的资源,并且不会从缓存中传递它,而是从服务器中重新下载它。
这可以形成一个非常简单而有效的缓存策略:默认情况下,您可以相当“积极”地缓存,并使您的资源在不久的将来(例如从现在开始的一年)过期。这是通过将资源标记为高“最大寿命”值来完成的:
Request: about_v1.js
Response: Cache-Control: max-age=31536000
如果您需要使资源“无效”(意味着您要从服务器重新下载新资源),则可以简单地为其赋予一个新名称(从而使用一个新的 URL)。
Request: about_v3.js
Response: with its new URL, the file is not present in the cache and therefore loaded fresh
许多 Web 框架开箱即用地使用了这种策略:他们使用“版本数字”丰富 CSS 和 JavaScript 文件的名称,将“home.css”转换为“home_377588.css”之类的东西。如果文件的内容更改,其标识符也将更改。在页面中引用该文件时,新标识符使它成为浏览器的未知资源 - 并重新下载。
这样,我们不必过多地处理缓存的复杂性,并且仍然拥有一个非常健壮而又简单的机制。
使用 GZIP 压缩
一些优化技术需要花费很多精力才能实现。但是,另一方面,还有很多“去皮水果”:在这种情况下,GZIP 就像香蕉一样,已经被剥皮并切成一口大小的碎片 - 因为它很容易实现。然而,它的影响却是巨大的:GZIP 通常会将文件大小减少 60% 或更多!
但是,在我们迷失于兴奋和赞美之前,让我们简单地谈谈它是如何工作的。
压缩基于文本的内容
GZIP 是一种压缩算法,可用于任何字节流。尽管其实现的细节相当复杂,但其结果却易于理解:文件的内容经过高度优化,以减小文件的大小。
当然,较小的文件意味着用户必须下载较少的数据。而下载更少的数据意味着我们的网页可以更快地显示!如前所述,GZIP 理论上可以用于任何类型的内容。但是,重要的是要知道它最适合基于文本的内容。这非常适合缩小 CSS,JS,HTML 和 XML 文件。另一方面,已经使用其他算法压缩的资源无法从使用 GZIP 进行的(额外)压缩中受益。因此,不建议将其用于大多数图像格式。
启用 GZIP 压缩
关于 GZIP 的最好之处在于,作为开发人员,您几乎不需要执行任何操作:在远程方面,您的 Web 服务器完全能够压缩文件。在客户端,任何现代的 Web 浏览器也都知道如何处理压缩资源。
我们要做的就是确保将我们的 Web 服务器配置为提供压缩资源。只是为了给您一个想法,这是一个(简化的)示例,说明了这种配置对于 Apache 的影响:
<IfModule mod_deflate.c>
AddOutputFilterByType DEFLATE text/css
AddOutputFilterByType DEFLATE text/html
AddOutputFilterByType DEFLATE text/javascript
AddOutputFilterByType DEFLATE text/plain
AddOutputFilterByType DEFLATE text/xml
</IfModule>
要获得完整而广泛的配置,请查看 HTML5 Boilerplate 项目及其服务器配置的汇编。这些配置中的“gzip”部分将为您提供经过验证的设置。
多域提供资源
下载资源时,浏览器会限制它们建立的同时连接数。通常,可以并行下载 2 到 8 个文件 - 其余文件需要等待。因此,从性能的角度来看,即使文件很小也很重要。实际的下载时间不会很长也没关系:只有在下载队列中的某个位置可用时,下载才会开始。
这些连接限制,如果强加在不同的域呢,简单的操作为我们提供了一些优化的余地:例如,如果您的网站在 「bookcc.top」 上运行,则可以使用 「assets.bookcc.top」 之类的其他域来提供资源。浏览器将能够并行建立到这些域中每个域的 2-8 个连接,您同时下载的数量就会增加一倍!
但是,在您无限制通过使用太多不同的域,则 DNS 或许会发现并惩罚,包括但不限于黑名单或限速。自己限制为 2-3 个其他主机域,您将充分利用此技术。
浏览器限制了同时下载的资源数量。但是,此限制适用于单个域,因此您可以通过向多个域提出请求来促进并行下载。
使用边缘网络(CDN)
如何快速的资源下载取决于许多因素。一个重要的因素是地理位置:客户端和服务器之间相距多远?如果它们彼此靠近,则延迟将很小并且下载将很快。它们距离越远,文件字节必须经过的时间就越长。
如果您的网站仅允许来自特定地理区域的访问者,那么最好在附近的托管公司租用服务器硬件。但是,如果您的网站有来自世界各地的访问者,则应考虑使用内容交付网络(简称:CDN)。
CDN 是分布在世界各地的服务器的集合。其背后的想法很简单:当用户访问网站时,请始终从尽可能靠近的位置提供文件。让我们举个例子:如果您选择的 CDN 服务在北美拥有一台服务器,而在欧洲拥有一台服务器,那么欧洲硬件将为来自法国的访问者提供服务,而北美将为来自加拿大的访问者提供服务。
在幕后,要完成这项工作,需要大量的逻辑运算和硬件支持。好消息是,所有这一切都由 CDN 服务提供商为您处理。您只需将简单的把 URL 放入 HTML 中。CDN 决定从哪里有效地提供图像,CSS 或 JavaScript 文件。
使用 CDN 服务有以下好处:
速度 - CDN 通过从服务器尽可能靠近用户处提供资产来减少网络延迟。
并行下载 - 浏览器限制了从每个域进行并行下载的次数。使用 CDN,您的资产将通过其他不同的主机名提供服务。这样,浏览器可以并行下载更多资源。
简便性 - 将您的静态资产(图像,CSS,JavaScript,PDF,视频等)移动到 CDN 非常容易。其他优化策略可能需要更改整个应用程序体系结构以极大地改善性能。
可伸缩性 - 将资产放在 CDN 上可以减轻服务器交付资产的负担,处理更多的流量和用户。
使用内容交付网络是加快网站访问速度的简便方法:从尽可能靠近访问者的位置交付资产可以大幅度提速。
优化 CSS & JavaScript
以前,我们曾讨论过如果要拥有快速加载的网页,减少 HTTP 请求的重要性。那么,将所有 CSS 和 JavaScript 内联到需要它的 HTML 页面的源代码中是否合乎逻辑呢?显而易见的好处是,我们将保存一些 HTTP 请求,因为不再需要分别下载 CSS 和 JavaScript。
但是,有一个很大的陷阱:我们将不得不在每次后续页面加载时将这些内容再次传输给用户。有了这样的策略,您将完全错过缓存的优点。因此,最好不要在页面的 HTML 中包含 CSS 和 JavaScript,而最好将它们作为单独的资源来提供。只有这样才能有效地缓存它们。
同样,本着尽量减少 HTTP 请求的精神,请记住,您应交付尽可能少的文件。当涉及到 CSS 和 Javascript 时,有许多预处理工具可让您将多个源文件组合成一个(或者更少)输出文件。
最小化 CSS 和 JavaScript
可读文本和优化文本实际上是两种。例如,对于我们作为开发人员而言,在我们的 JavaScript 文件中添加注释非常有意义。但是,浏览器的 JavaScript 解释器并不关心这些。它们只是一个多余的负担,使文件超出了必须的大小。
/* This is the original CSS code.
Including comments, lots of white space, ... */
p {
text-align: center;
}
div {
background: red;
}
尽管注释是一个非常明显的例子,但为浏览器优化 CSS 和 JavaScript 的工作远不止于此:我们可以没有空格和换行符;我们可以缩短变量名;我们可以结合重复的 CSS 选择器规则…
p{text-align:center}div{background:red}
综上所述,所有这些(以及更多其他)措施被称为“最小化”。他们的目标是一个目标:减少字符,从而减小文件大小,这是快速加载网页的基础指标。对我们来说幸运的是,我们不必重新学习就可以编写没有空白或注释的 JavaScript 和 CSS。当“最小化”我们的资源时,这里有足够的强大工具来帮助我们。
Frameworks
如果您使用的是 Ruby on Rails 或 Django 之类的应用程序框架,则可能已经安装了一个缩小工具。检查您的框架文档,看是否有内置的东西。
Grunt & Gulp
如果您在工作流程中使用 Grunt 或 Gulp,那么有很多插件可以“丑化”和“缩小”。
JavaScript:grunt-contrib-uglify 和 gulp-uglify
CSS:grunt-contrib-cssmin 和 gulp-minify -css
Desktop Apps
如果您希望使用独立的桌面应用程序来完成此工作,则应查看 CodeKit 和 Prepros 之类的工具。
在页面中包含 CSS
您可能会想当然地认为包括 CSS 确实是轻而易举的事。而且您几乎是对的,但是“关键渲染路径”(浏览器渲染页面的方式)提供了一些优化机会。默认情况下,浏览器必须等到所有 CSS 资源下载完毕后才能开始呈现页面。广义上讲,这意味着您拥有的 CSS 越多,页面开始绘制的时间就越晚。
但是,我们可以做一些事情来优化这一点。
媒体类型和查询
包括样式时,media 属性会很有帮助。例如,通过将其标记为“打印”,浏览器将不必等待下载和解析它。
<link href="print-styles.css" rel="stylesheet" media="print">
使 CSS 成为所谓的“非阻塞资源”的另一种方法是使用媒体查询。然后,浏览器可以自行决定是否必须下载 CSS(从而延迟页面的呈现)。在此示例中,仅在确实需要此特定 CSS 的较小屏幕上阻止渲染:
<link href="small-screens.css" rel="stylesheet" media="(max-width: 480px)">
尽早包含 CSS
由于浏览器(默认情况下)必须等待所有 CSS 加载,因此尽快提供它很重要。我们已经讨论了您可以做的几件事:缩小 CSS 文件并使用 GZIP 压缩它们。
但是,还有另一种非常简单的方法来确保浏览器尽早接收 CSS 通过在 HTML 文档的 HEAD 部分中早些包含 CSS,这样,浏览器将尽快开始下载 CSS。
不要使用 @import
CSS 允许直接从 CSS 文件中“导入”其他样式表文件:
@import url('style.css');
但是,您应尽一切努力避免这种机制。提出此建议的原因很简单:CSS @import 会延迟页面的渲染!
举个例子,假设您在页面中包含一个名为“styles-1.css”的文件。如果该文件中的某处使用@import
语句从“styles-2.css”加载其他 CSS,则该过程将大大减慢速度:
- 首先,像往常一样,必须下载并解析“styles-1.css”。
- 只有在解析完成后,浏览器才会注意到引用了另一个文件“styles-2.css”。
- 然后,它也必须下载并解析此文件,然后才能最终开始呈现页面。
当然,@import
语句曾经被发明是有充分的理由的:它允许将 CSS 模块保持在单独的文件中。这个基本原则是完全合理的,您不应该放弃它!
但是,生产 CSS 并非合适的选择。看一下 Sass 和 Less 预处理器框架,其中也可以使用@import
机制,但没有负面影响。
加载 JavaScript
与 CSS 相似,JavaScript 默认情况下会“阻塞”资源:浏览器将停止构建页面,以便下载和解析刚遇到的 JavaScript。只有完成后,它才能继续呈现页面。尤其是使用大量 JavaScript(这在当今的动态和脚本繁重的页面上非常常见)时,这将使您的访问者难以等到最终看到的页面。
在底部加载脚本
改善这种情况的一种方法是在 HTML 文档的最底部(紧接在关闭 body 标记之前)包含 JavaScript 资源。这使浏览器可以平静地构造文档对象模型和 CSS 对象模型的大部分。
在 JavaScript “打断”渲染过程的其余部分之前,开始显示您的页面。
Async 脚本
更好的方法是明确告知浏览器某些 JavaScript 不应阻止呈现过程。您可以通过在脚本标签中添加“async”属性来做到这一点:
<script src="page.js" async></script>
该解决方案应满足大多数需求。如果您想进一步探讨该问题,那么类似 Page Speed 的网络工具提供更多阅读材料。
托管加载 JavaScript
网站的大部分 JavaScript 都将针对该网站进行自定义编码。但是大多数网站还包括 jQuery 或 AngularJS 之类的通用库。尽管您可以从自己的 Web 服务器上提供这些服务,但是还有另一个选择:存在一些公共服务,它们在自己的 Content Delivery Networks 上托管流行的库,并使开发人员可以免费使用它们。
包括其中一个 CDN 库有以下优点:
- 可靠性和速度:就可靠性和速度而言,很难击败这些服务。
- 并行 HTTP 连接:浏览器限制到同一服务器的同时连接数。
- 浏览器缓存:浏览器很可能会从其缓存中提供该缓存!例如,访问者已经很可能已经在另一个网站上下载了该资源。
仅加载一次脚本
尽管这条建议很明显,但它仍然经常被忽视:特别是在较大的团队中,不同的开发人员多次包含相同的第三方库并不罕见。不用说,这是带宽特别悲惨的浪费。
写在最后
如果您按照本指南中的提示与技巧进行操作,则您的网站仍然不完美(对此感到抱歉…)。但是它肯定更精简,更快,从而保证了一件重要的事情:对您的访客来说,这是一种更好的体验。
希望能帮助您的网站在迈向更好的过程中迈出第一步。