what is webp
webp 是由 Google 收购 On2 Technologies 后发展出来的格式,以BSD授权条款发布。目前已经在不同厂商之间进行了尝试,如Google、Facebook、ebay、百度、腾讯、淘宝等。
webp支持有损压缩和无损压缩,可以使用于大多数的图片、半透明、透明都可以;并且有损压缩的程度是可以调节的,用户可以在文件大小和图像质量之间作出权衡,根据研究,webp通常可以比jpg和jpeg图像在不损失图像质量的情况下,体积缩小30%。
目前只有Chrome、Opera和最新版的Edge浏览器支持webp,不过Firefox也在开发计划中自持webp,不过现在已经支持webp的浏览器已经占到首场份额的75%,这已经让我们有足够的动力,让我们去使用webp了。
How can I detect browser support for WebP
在google开发者平台提供了关于检测浏览器是否支持webp的方法:
Request Header
浏览器在支持 webp 图片格式的情况下,会在请求的 http header accept 中携带 webp/image 的字段,后端接收到请求之后可以按照该形式来判断是否返回 webp 图片内容。
前端代码检测是否支持webp格式的图片
// check_webp_feature:
// 'feature' can be one of 'lossy', 'lossless', 'alpha' or 'animation'.
// 'callback(feature, result)' will be passed back the detection result (in an asynchronous way!)
function check_webp_feature(feature, callback) {
var kTestImages = {
lossy: "UklGRiIAAABXRUJQVlA4IBYAAAAwAQCdASoBAAEADsD+JaQAA3AAAAAA",
lossless: "UklGRhoAAABXRUJQVlA4TA0AAAAvAAAAEAcQERGIiP4HAA==",
alpha: "UklGRkoAAABXRUJQVlA4WAoAAAAQAAAAAAAAAAAAQUxQSAwAAAARBxAR/Q9ERP8DAABWUDggGAAAABQBAJ0BKgEAAQAAAP4AAA3AAP7mtQAAAA==",
animation: "UklGRlIAAABXRUJQVlA4WAoAAAASAAAAAAAAAAAAQU5JTQYAAAD/////AABBTk1GJgAAAAAAAAAAAAAAAAAAAGQAAABWUDhMDQAAAC8AAAAQBxAREYiI/gcA"
};
var img = new Image();
img.onload = function () {
var result = (img.width > 0) && (img.height > 0);
callback(feature, result);
};
img.onerror = function () {
callback(feature, false);
};
img.src = "data:image/webp;base64," + kTestImages[feature];
}
当判断当前浏览器支持webp的时候,可以在localStorage中存储一个状态,方便后面JS使用;另外一方面可以给body元素添加一个webpa
的class,方便以后的css选择器使用。
Using Webp In HTML
使用HTML5的新元素picture,可以使用source,使浏览器支持webp的时候,优先选择webp的图片加载webp图片。
<picture>
<source
srcset="image.webp"
type="image/webp" >
<img
src="image.jpg"
type="image/jpeg"
alt="image description">
</picture>
Using Webp In CSS
上面提到的我们可以在判断浏览器支持webp之后,给body元素添加一个webpa
class,这个时候我们就可以配合css与处理器less或者sass和css选择器的权重使用了
// webp兼容性方案
.webpbg(@url) {
background-image: url(@url);
.webpa & {
background-image: url('@{url}.webp');
}
}
.test {
height: 500px;
width: 100%;
.webpbg('./bg.jpg')
}
编译之后的css文件为:
.test {
height: 500px;
width: 100%;
background-image: url('./bg.jpg');
}
.webpa .test {
background-image: url('./bg.jpg.webp');
}
Using Webp In Lazy Load
图片大量使用的时候我们会使用懒加载进行图片的延迟加载。这时就可以修改懒加载插件,在插件里动态兼容webp图片了:
function getWebpSrc(imgsrc,webpimgsrc) {
var needwebp = false,
src = ''
if (window.localStorage && typeof localStorage === 'object') {
needwebp = localStorage.getItem('webpsupport') === 'true'
}
src = needwebp ? webpimgsrc : imgsrc
return src
}
const imgSmall = document.querySelector('.img-small')
const loadImage = (() => {
const img = new Image()
img.src = imgSmall.src
img.addEventListener('load', (e) => {
imgSmall.classList.add('loaded')
}, false)
const imgLarge = new Image()
imgLarge.src = getWebpSrc(imgSmall.dataset.large,imgSmall.dataset.largewebp)
imgLarge.addEventListener('load', (e) => {
imgLarge.classList.add('loaded')
}, false)
imgSmall.parentNode.appendChild(imgLarge)
})()
Generate Webp
上面介绍了webp的基本的使用的方法,那么如何生产webp的图片,主要有一下两种思路,第一是前端生成静态的webp的图片,托管在服务器上,第二种是服务端动态生成webp的图片。
生成静态webp图片
使用imagemin
可以生成webp的图片,简单的使用方法如下:
var imagemin = require("imagemin"), // The imagemin module.
webp = require("imagemin-webp"), // imagemin's WebP plugin.
outputFolder = "./img", // Output folder
PNGImages = "./img/*.png", // PNG images
JPEGImages = "./img/*.jpg"; // JPEG images
imagemin([PNGImages], outputFolder, {
plugins: [webp({
lossless: true // Losslessly encode images
})]
});
imagemin([JPEGImages], outputFolder, {
plugins: [webp({
quality: 65 // Quality setting from 0 to 100
})]
});
另外一种是在前端资源打包的时候,利用webpack的loader,来生成webp,不过这样会严重拖慢打包的速度,故不如直接用node.js生成图片
服务端动态生成webp
nginx+lua+graphicsmagick
这套方案其实做的事情就是nginx对域名进行拦截,lua脚本进行域名后缀规则的匹配,比如说300x300.png/.webp类似的后缀,匹配完成后再在lua里调用graphicsmagick的命令,进行一些图片转换、裁剪等工作。
if table.isLegal(size_list) and extend == "webp" then
command = [[/usr/local/GraphicsMagick-1.3.25/bin/gm convert -quality 75 -density 72 +profile "*" ]] .. ngx.var.image_root .. originalUri .. " -geometry " .. area .. " " .. ngx.var.file;
os.execute(command);
end