具有 WebP 回退和数据源的背景图像
Background Image with WebP fallback and data-src
所以我正在我的网站上做一些优化工作以提高 Page Insights 分数,我可以解决的两点是:-
- 以下一代格式提供图像
- 延迟屏幕外图像
所以下一代格式的图像,我决定使用 WebP,但需要包括回退以便它们在所有 browsers/devices 中工作。
延迟屏幕外图像;我使用 data-src
和一些 JS 脚本将背景图像设置为数据源,JS 替换了初始 SRC,即 src="data:image/png;base64,R0lGODlhAQABAAD/ACwAAAAAAQABAAACADs="
以下面的例子为例,我将如何在延迟屏幕外图像的同时使用带有回退的 WebP 的内联背景图像?
HTML
<div id="working-bg" class="parallax" data-src="/wp-content/uploads/2016/08/silva-planning-parralax.jpg" style="background-image: url(/wp-content/uploads/2016/08/silva-planning-parralax.jpg)"></div>
用于数据源的 JS
<script>
function init() {
var imgDefer = document.getElementsByTagName('img');
for (var i=0; i<imgDefer.length; i++) {
if(imgDefer[i].getAttribute('data-src')) {
imgDefer[i].setAttribute('src',imgDefer[i].getAttribute('data-src'));
} }
var imgDeferSpan = document.querySelectorAll('span[data-src]');
var styleSpan = "background-image: url({url})";
for (var i = 0; i < imgDeferSpan.length; i++) {
imgDeferSpan[i].setAttribute('style', styleSpan.replace("{url}", imgDeferSpan[i].getAttribute('data-src')));
}
var imgDeferDiv = document.querySelectorAll('div[data-src]');
var styleDiv = "background-image: url({url})";
for (var i = 0; i < imgDeferDiv.length; i++) {
imgDeferDiv[i].setAttribute('style', styleDiv.replace("{url}", imgDeferDiv[i].getAttribute('data-src')));
}
}
window.onload = init;
</script>
提前致谢!
以下一代格式提供图像:
使用像 imagekit.io 这样的图像 CDN,并自动为您完成。大多数图像 CDN 都有免费计划,非常适合测试和小型站点。
延迟屏幕外图像:
使用像 lozad.js 这样的现成解决方案,它可以同时处理图像和背景图像。对于背景图像,您可以跳过设置初始内联样式,因为该元素已设置其大小,并且在图像加载时不会导致任何重排。对于 <img>
s,使用空的 <svg>
作为初始 src
值,其中 viewBox
中的 6 9
定义了宽度 (6) 和高度 (9) 之间的关系) => 更改这些值以适合您的上下文。
data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 6 9'%3E%3C/svg%3E
请注意,lozad.js 使用的 Intersection Observer API 仍然缺乏浏览器支持,因此请务必添加一个 polyfill。
祝你好运!
编辑:答案不正确,已将其删除
在提供图像的后端检查 webp 支持应该是正确的解决方案,如果支持,只需重定向到 webp 版本。或者在 JS 中做同样的事情,或者另一个 hacky 解决方案可以,如果你没有更好的方法是加载带有 webp 版本的 img 标签,然后 onerror (<img onerror='loadJpg(this)/>
) 加载原始版本作为后备,并使 #bg.style.backgroundImage = img.src
,它应该在 img.src
更改时更新
以下一代格式提供图像:
将 *.jpeg 或 *.png 图像转换为 *.jpeg.webp 或 *.png.webp 并配置服务器以有条件地传送 webp。
<IfModule mod_mime.c>
AddType image/webp .webp
</IfModule>
<ifModule mod_rewrite.c>
RewriteEngine On
RewriteBase /
RewriteCond %{HTTP_ACCEPT} image/webp
RewriteCond %{REQUEST_URI} (?i)(.*)\.(jpe?g|png)$
RewriteCond %{DOCUMENT_ROOT}%1\.%2.webp -f
RewriteRule (?i)(.*)\.(jpe?g|png)$ %1\.%2\.webp [T=image/webp,E=webp:1,L]
<IfModule mod_headers.c>
Header append Vary Accept env=REDIRECT_webp
</IfModule>
</IfModule>
延迟屏幕外图像:
向 <img>
个元素添加 loading=lazy 属性。
这是我的解决方案。这与 Tamás 的回答有点不同。
使用可选的 class 包含您可以设置图像的大小。
onload 事件确保了最终图像的能力。
您加载带有隐藏图片元素的图像,并使用 js 获取加载的图像(回退为 jpg 或 png)。最后,您将带有 jquery 的加载图像设置为父级 div 的背景。
也许现场有更好的解决方案,但这对我有用。
function makeBgImage( img ){
let srcImage;
if ( typeof img.currentSrc === "undefined" ){
//Old browser
srcImage = img.src;
}else{
//Modern browser
srcImage = img.currentSrc;
}
let ref = $(img).parents('div:first');
ref.css('background', 'url(' + srcImage + ')');
if( ref.hasClass('contain') ){
ref.css('background-size', 'contain');
}else{
ref.css('background-size', 'cover');
}
ref.css('background-position', 'center');
ref.css('background-repeat', 'no-repeat');
}
.hidden{display: none;}
.img-container{
width: 100%;
padding-top: 62.5%; /* 8:5 Aspect Ratio */
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div class="img-container">
<picture class="hidden">
<source srcset="image.webp" type="image/webp">
<img onload="makeBgImage(this)" alt="Image" src="image.png">
</picture>
</div>
所以我正在我的网站上做一些优化工作以提高 Page Insights 分数,我可以解决的两点是:-
- 以下一代格式提供图像
- 延迟屏幕外图像
所以下一代格式的图像,我决定使用 WebP,但需要包括回退以便它们在所有 browsers/devices 中工作。
延迟屏幕外图像;我使用 data-src
和一些 JS 脚本将背景图像设置为数据源,JS 替换了初始 SRC,即 src="data:image/png;base64,R0lGODlhAQABAAD/ACwAAAAAAQABAAACADs="
以下面的例子为例,我将如何在延迟屏幕外图像的同时使用带有回退的 WebP 的内联背景图像?
HTML
<div id="working-bg" class="parallax" data-src="/wp-content/uploads/2016/08/silva-planning-parralax.jpg" style="background-image: url(/wp-content/uploads/2016/08/silva-planning-parralax.jpg)"></div>
用于数据源的 JS
<script>
function init() {
var imgDefer = document.getElementsByTagName('img');
for (var i=0; i<imgDefer.length; i++) {
if(imgDefer[i].getAttribute('data-src')) {
imgDefer[i].setAttribute('src',imgDefer[i].getAttribute('data-src'));
} }
var imgDeferSpan = document.querySelectorAll('span[data-src]');
var styleSpan = "background-image: url({url})";
for (var i = 0; i < imgDeferSpan.length; i++) {
imgDeferSpan[i].setAttribute('style', styleSpan.replace("{url}", imgDeferSpan[i].getAttribute('data-src')));
}
var imgDeferDiv = document.querySelectorAll('div[data-src]');
var styleDiv = "background-image: url({url})";
for (var i = 0; i < imgDeferDiv.length; i++) {
imgDeferDiv[i].setAttribute('style', styleDiv.replace("{url}", imgDeferDiv[i].getAttribute('data-src')));
}
}
window.onload = init;
</script>
提前致谢!
以下一代格式提供图像: 使用像 imagekit.io 这样的图像 CDN,并自动为您完成。大多数图像 CDN 都有免费计划,非常适合测试和小型站点。
延迟屏幕外图像:
使用像 lozad.js 这样的现成解决方案,它可以同时处理图像和背景图像。对于背景图像,您可以跳过设置初始内联样式,因为该元素已设置其大小,并且在图像加载时不会导致任何重排。对于 <img>
s,使用空的 <svg>
作为初始 src
值,其中 viewBox
中的 6 9
定义了宽度 (6) 和高度 (9) 之间的关系) => 更改这些值以适合您的上下文。
data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 6 9'%3E%3C/svg%3E
请注意,lozad.js 使用的 Intersection Observer API 仍然缺乏浏览器支持,因此请务必添加一个 polyfill。
祝你好运!
编辑:答案不正确,已将其删除
在提供图像的后端检查 webp 支持应该是正确的解决方案,如果支持,只需重定向到 webp 版本。或者在 JS 中做同样的事情,或者另一个 hacky 解决方案可以,如果你没有更好的方法是加载带有 webp 版本的 img 标签,然后 onerror (<img onerror='loadJpg(this)/>
) 加载原始版本作为后备,并使 #bg.style.backgroundImage = img.src
,它应该在 img.src
更改时更新
以下一代格式提供图像:
将 *.jpeg 或 *.png 图像转换为 *.jpeg.webp 或 *.png.webp 并配置服务器以有条件地传送 webp。
<IfModule mod_mime.c>
AddType image/webp .webp
</IfModule>
<ifModule mod_rewrite.c>
RewriteEngine On
RewriteBase /
RewriteCond %{HTTP_ACCEPT} image/webp
RewriteCond %{REQUEST_URI} (?i)(.*)\.(jpe?g|png)$
RewriteCond %{DOCUMENT_ROOT}%1\.%2.webp -f
RewriteRule (?i)(.*)\.(jpe?g|png)$ %1\.%2\.webp [T=image/webp,E=webp:1,L]
<IfModule mod_headers.c>
Header append Vary Accept env=REDIRECT_webp
</IfModule>
</IfModule>
延迟屏幕外图像:
向 <img>
个元素添加 loading=lazy 属性。
这是我的解决方案。这与 Tamás 的回答有点不同。 使用可选的 class 包含您可以设置图像的大小。 onload 事件确保了最终图像的能力。 您加载带有隐藏图片元素的图像,并使用 js 获取加载的图像(回退为 jpg 或 png)。最后,您将带有 jquery 的加载图像设置为父级 div 的背景。 也许现场有更好的解决方案,但这对我有用。
function makeBgImage( img ){
let srcImage;
if ( typeof img.currentSrc === "undefined" ){
//Old browser
srcImage = img.src;
}else{
//Modern browser
srcImage = img.currentSrc;
}
let ref = $(img).parents('div:first');
ref.css('background', 'url(' + srcImage + ')');
if( ref.hasClass('contain') ){
ref.css('background-size', 'contain');
}else{
ref.css('background-size', 'cover');
}
ref.css('background-position', 'center');
ref.css('background-repeat', 'no-repeat');
}
.hidden{display: none;}
.img-container{
width: 100%;
padding-top: 62.5%; /* 8:5 Aspect Ratio */
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div class="img-container">
<picture class="hidden">
<source srcset="image.webp" type="image/webp">
<img onload="makeBgImage(this)" alt="Image" src="image.png">
</picture>
</div>