采用 WebP 动态响应图片
你可能听过WebP图片格式。相比于 PNG 图片,其文件大小能够节省 26%;相比于 JPEG 图片,能够节省大约 25%。
图片在如今的站点上不可或缺。试想一下,在我们网页上没有图片会怎样?高质量的图片能够使你的站点更加出色,但同时伴随着一定的性能损耗。由于图片文件较大,下载时间相对较长并且会减缓页面的加载。如果是一个带宽较低的用户,用户体验将会特别差。
在移动设备上面,这种现象会更加明显。在移动设备上加载大型图片消耗时间取决你的网络以及连接速度。如果你是一个不耐心的用户,你将会变得沮丧。幸运的是,我们有能力处理 响应式图片 。通过使用 picture 标签,我们可以根据用户的设备为用户提供不同大小、设备像素比(DPR)以及格式的图片。例如,下面的代码就可以做到这一点。
<picture>
<source
media="(min-width: 1024px)"
srcset="./images/brooklyn.jpg, ./images/brooklyn-2x.jpg 2x, ./images/brooklyn-3x.jpg 3x"
type="image/jpeg">
<source
media="(min-width: 320px)"
srcset="./images/brooklyn-small.jpg, ./images/brooklyn-small-2x.jpg 2x, ./images/brooklyn-small-3x.jpg 3x"
type="image/jpeg">
</picture>
在上面的代码中,我们指定不同的图像大小及其相应的设备像素比给给定的屏幕宽度。使用 picture 标签,浏览器可以基于设备决定最佳的内容。以上的代码可以完美运行,我们可以进一步扩展,以适应更多的场景。
你可能听过WebP图片格式。相比于 PNG 图片,其文件大小能够节省 26%;相比于 JPEG 图片,能够节省大约 25%-34%。目前,Chrome、Opera 以及 Android 能够支持 WebP 格式,但 Safari 和 IE 尚未支持。既然我们能够用 picture 标签来处理响应式图片,我们也能够使用 WebP 格式的图片并且允许浏览器在不支持 WebP 时进行回退。
让我们在上面代码的基础上,添加 WebP 图片的支持。同时,我们要确保能够根据不同的 DPR 使用最佳视觉效果的图片。
<picture>
<!-- JPEG Images -->
<source
media="(min-width: 1024px)"
srcset="./images/brooklyn.jpg, ./images/brooklyn-2x.jpg 2x, ./images/brooklyn-3x.jpg 3x"
type="image/jpeg">
<source
media="(min-width: 320px)"
srcset="./images/brooklyn-small.jpg, ./images/brooklyn-small-2x.jpg 2x, ./images/brooklyn-small-3x.jpg 3x"
type="image/jpeg">
<!-- WebP Images -->
<source
media="(min-width: 1024px)"
srcset="./images/brooklyn.webp, ./images/brooklyn-2x.webp 2x, ./images/brooklyn-3x.webp 3x"
type="image/webp">
<source
media="(min-width: 320px)"
srcset="./images/brooklyn-small.webp, ./images/brooklyn-small-2x.webp 2x, ./images/brooklyn-small-3x.webp 3x"
type="image/webp">
<!-- The fallback image -->
<img
src="./images/brooklyn.jpg" alt="Brooklyn Bridge - New York">
</picture>
在上面的代码中,我们已经创建了能够同时使用 JPEG 和 WebP 图片的 picture 标签。浏览器将根据设备决定最佳的选项。由于 WebP 并不支持 IE 和 Safari,使用 WebP 图片意味着你需要在服务器上同时保存 WebP 和 JPEG 格式的图片副本。上面的代码足够满足我们当前的需求,但试想一下如果每张采用这种方式来编写,代码将会变得非常臃肿。当你的站点开始增长时,为每张图片编写上面的代码将会变得非常乏味。这时候,便可以采用 Service Workers 来解决这个问题。
我们采用开发者工具观察 HTTP 请求头部,可以看出可以根据 Accept 头部来判断我们的浏览器是否支持 WebP 图片。为了利用这一点,并开始提供 WebP 图片,我们需要注册一个 Service Worker。Service Worker 的一大特性就是,它们能够拦截网络请求,这样子,我们就能够完全控制响应内容。使用这个特性,我们能够监听 HTTP 头部,并决定如何做。如果你想了解更多关于 Service Workers 的内容,可以看看这个 Github 库获取更多的信息。
我们在 html 页面添加如下代码用于注册 Service Worker。以下的代码引用 service-worker.js 文件。
<script>
// Register the service worker
if ('serviceWorker' in navigator) {
navigator.serviceWorker.register('/service-worker.js').then(function(registration) {
// Registration was successful
console.log('ServiceWorker registration successful with scope: ', registration.scope);
}).catch(function(err) {
// registration failed :(
console.log('ServiceWorker registration failed: ', err);
});
}
</script>
在上面的代码中,我们做了一个简单的检查,判断浏览器是否支持 Service Worker,如果支持,注册并安装 Service Worker。这段代码代码最好的地方就是做了兼容处理,如果浏览器不支持 Service Workers,它们会自动回退并且用户不会注意到其中差别。
接下来,我们需要创建 Service Worker 文件‘service-worker.js‘,用于拦截正在传递到服务器的请求。
"use strict";
// Listen to fetch events
self.addEventListener('fetch', function(event) {
// Check if the image is a jpeg
if (/\.jpg$|.png$/.test(event.request.url)) {
// Inspect the accept header for WebP support
var supportsWebp = false;
if (event.request.headers.has('accept')){
supportsWebp = event.request.headers
.get('accept')
.includes('webp');
}
// If we support WebP
if (supportsWebp)
{
// Clone the request
var req = event.request.clone();
// Build the return URL
var returnUrl = req.url.substr(0, req.url.lastIndexOf(".")) + ".webp";
event.respondWith(
fetch(returnUrl, {
mode: 'no-cors'
})
);
}
}
});
上面的示例代码做了一系列的事情,让我们来一步步分解。
在前面几行,我添加一个事件监听器来监听任何一个 fetch 事件。当每个请求发生时,先判断当前的请求是否是获取 JPEG 或者 PNG 格式的图片。如果当前的请求是获取图片,我就能根据 HTTP 请求头部来决定最佳的响应。在这种情况下,我通过检查 Accept 头部并且查找是否存在“image/webp“ Mime 类型。一旦查询完头部的值,我就能确定浏览器是否支持 WebP 图片,如果浏览器支持 WebP 图片,就返回相应的 WebP 图片。
现在,我们的 HTML 看起来比较整洁,能够支持 WebP 图片而并不臃肿。
<picture>
<source
media="(min-width: 1024px)"
srcset="./images/brooklyn.jpg, ./images/brooklyn-2x.jpg 2x, ./images/brooklyn-3x.jpg 3x"
type="image/jpeg">
<source
media="(min-width: 320px)"
srcset="./images/brooklyn-small.jpg, ./images/brooklyn-small-2x.jpg 2x, ./images/brooklyn-small-3x.jpg 3x"
type="image/jpeg">
</picture>
Service Workers 给了我们无限的可能。在这个例子中,我们可以扩展到包括其他图片格式,甚至是缓存。你还能轻松地添加支持 IE 的 JPEGXR 。这样子,我们能够更快地给我们的用户展示我们的页面。
如果你想看看示例代码运行的效果,请移步到 deanhume.github.io/Service-Workers-WebP 。打开支持这些特性的浏览器,如 Chrome,打开开发者工具,就可以看到页面的运行。
参考资料
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

上一篇: PHP 预定义常量
下一篇: 彻底找到 Tomcat 启动速度慢的元凶
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论