Làm cách nào để phát hiện hỗ trợ cho WebP qua Javascript? Tôi muốn sử dụng phát hiện tính năng hơn là phát hiện trình duyệt nếu có thể, nhưng tôi không thể tìm ra cách để làm như vậy. Modernizr ( www.modernizr.com ) không kiểm tra nó.
Làm cách nào để phát hiện hỗ trợ cho WebP qua Javascript? Tôi muốn sử dụng phát hiện tính năng hơn là phát hiện trình duyệt nếu có thể, nhưng tôi không thể tìm ra cách để làm như vậy. Modernizr ( www.modernizr.com ) không kiểm tra nó.
Câu trả lời:
Đây là giải pháp của tôi - mất khoảng 6ms và tôi đang coi WebP chỉ là một tính năng cho trình duyệt hiện đại. Sử dụng một cách tiếp cận khác bằng cách sử dụng hàm canvas.toDataUrl () thay vì hình ảnh như một cách để phát hiện tính năng:
function support_format_webp()
{
var elem = document.createElement('canvas');
if (!!(elem.getContext && elem.getContext('2d')))
{
// was able or not to get WebP representation
return elem.toDataURL('image/webp').indexOf('data:image/webp') == 0;
}
else
{
// very old browser like IE 8, canvas not supported
return false;
}
}
webp = e => document.createElement('canvas').toDataURL('image/webp').indexOf('data:image/webp') == 0;
Tôi nghĩ một cái gì đó như thế này có thể hoạt động:
var hasWebP = false;
(function() {
var img = new Image();
img.onload = function() {
hasWebP = !!(img.height > 0 && img.width > 0);
};
img.onerror = function() {
hasWebP = false;
};
img.src = 'http://www.gstatic.com/webp/gallery/1.webp';
})();
Trong Firefox và IE, trình xử lý "onload" sẽ hoàn toàn không được gọi nếu không thể hiểu được hình ảnh và thay vào đó, "onerror" được gọi.
Bạn đã không đề cập đến jQuery, nhưng như một ví dụ về cách xử lý tính chất không đồng bộ của kiểm tra đó, bạn có thể trả về đối tượng jQuery "Deferred":
function hasWebP() {
var rv = $.Deferred();
var img = new Image();
img.onload = function() { rv.resolve(); };
img.onerror = function() { rv.reject(); };
img.src = 'http://www.gstatic.com/webp/gallery/1.webp';
return rv.promise();
}
Sau đó, bạn có thể viết:
hasWebP().then(function() {
// ... code to take advantage of WebP ...
}, function() {
// ... code to deal with the lack of WebP ...
});
Trình kiểm tra nâng cao hơn: http://jsfiddle.net/JMzj2/29/ . Cái này tải hình ảnh từ một URL dữ liệu và kiểm tra xem nó có tải thành công hay không. Vì WebP hiện cũng hỗ trợ hình ảnh không mất dữ liệu, bạn có thể kiểm tra xem trình duyệt hiện tại chỉ hỗ trợ WebP mất dữ liệu hay WebP không mất dữ liệu. (Lưu ý: Điều này mặc nhiên cũng kiểm tra hỗ trợ URL dữ liệu.)
var hasWebP = (function() {
// some small (2x1 px) test images for each feature
var images = {
basic: "data:image/webp;base64,UklGRjIAAABXRUJQVlA4ICYAAACyAgCdASoCAAEALmk0mk0iIiIiIgBoSygABc6zbAAA/v56QAAAAA==",
lossless: "data:image/webp;base64,UklGRh4AAABXRUJQVlA4TBEAAAAvAQAAAAfQ//73v/+BiOh/AAA="
};
return function(feature) {
var deferred = $.Deferred();
$("<img>").on("load", function() {
// the images should have these dimensions
if(this.width === 2 && this.height === 1) {
deferred.resolve();
} else {
deferred.reject();
}
}).on("error", function() {
deferred.reject();
}).attr("src", images[feature || "basic"]);
return deferred.promise();
}
})();
var add = function(msg) {
$("<p>").text(msg).appendTo("#x");
};
hasWebP().then(function() {
add("Basic WebP available");
}, function() {
add("Basic WebP *not* available");
});
hasWebP("lossless").then(function() {
add("Lossless WebP available");
}, function() {
add("Lossless WebP *not* available");
});
Giải pháp ưa thích trong HTML5
<picture>
<source srcset="/path/to/image.webp" type="image/webp">
<img src="/path/to/image.jpg" alt="insert alt text here">
</picture>
type="image/webp"
quan trọng là để trình duyệt bỏ qua nó nếu định dạng không xác định!
Cách chính thức của Google:
Vì một số trình duyệt cũ có hỗ trợ một phần cho webp , vì vậy tốt hơn là bạn nên nói rõ hơn tính năng webp nào bạn đang cố gắng sử dụng và phát hiện tính năng cụ thể này và đây là khuyến nghị chính thức của Google về cách phát hiện một tính năng webp cụ thể:
// check_webp_feature:
// 'feature' can be one of 'lossy', 'lossless', 'alpha' or 'animation'.
// 'callback(feature, isSupported)' 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];
}
Cách sử dụng ví dụ:
check_webp_feature('lossy', function (feature, isSupported) {
if (isSupported) {
// webp is supported,
// you can cache the result here if you want
}
});
Lưu ý rằng tải hình ảnh là không chặn và không đồng bộ . Điều này có nghĩa là bất kỳ mã nào phụ thuộc vào sự hỗ trợ của WebP tốt hơn nên được đưa vào hàm gọi lại.
Cũng lưu ý rằng các giải pháp đồng bộ khác sẽ không hoạt động tốt với Firefox 65
Đây là một câu hỏi cũ, nhưng Modernizr hiện đã hỗ trợ phát hiện Webp.
http://modernizr.com/download/
Tìm img-webp
trong phần Phát hiện không phải lõi.
Đây là phiên bản câu trả lời của James Westgate trong ES6.
function testWebP() {
return new Promise(res => {
const webP = new Image();
webP.src = 'data:image/webp;base64,UklGRjoAAABXRUJQVlA4IC4AAACyAgCdASoCAAIALmk0mk0iIiIiIgBoSygABc6WWgAA/veff/0PP8bA//LwYAAA';
webP.onload = webP.onerror = () => {
res(webP.height === 2);
};
})
};
testWebP().then(hasWebP => console.log(hasWebP));
FF64: sai
FF65: đúng
Chrome: true
Tôi thích câu trả lời đồng bộ từ Rui Marques, nhưng tiếc là FF65 vẫn trả về false mặc dù có khả năng hiển thị WebP.
Đây là mã mà không cần phải yêu cầu hình ảnh. Cập nhật với trò chơi mới của qwerty.
function testWebP(callback) {
var webP = new Image();
webP.onload = webP.onerror = function () {
callback(webP.height == 2);
};
webP.src = 'data:image/webp;base64,UklGRjoAAABXRUJQVlA4IC4AAACyAgCdASoCAAIALmk0mk0iIiIiIgBoSygABc6WWgAA/veff/0PP8bA//LwYAAA';
};
testWebP(function(support) {
document.body.innerHTML = support ? 'Yeah man!' : 'Nope';
});
WebPJS sử dụng phát hiện hỗ trợ WebP thông minh hơn mà không cần hình ảnh bên ngoài: http://webpjs.appspot.com/
Tôi thấy rằng tính năng phát hiện hỗ trợ webp yêu cầu 300 + ms khi trang có JavaScript nặng. Vì vậy, tôi đã viết một tập lệnh với các tính năng bộ nhớ đệm:
Nó sẽ chỉ phát hiện một lần khi người dùng truy cập trang lần đầu tiên.
/**
* @fileOverview WebP Support Detect.
* @author ChenCheng<sorrycc@gmail.com>
*/
(function() {
if (this.WebP) return;
this.WebP = {};
WebP._cb = function(isSupport, _cb) {
this.isSupport = function(cb) {
cb(isSupport);
};
_cb(isSupport);
if (window.chrome || window.opera && window.localStorage) {
window.localStorage.setItem("webpsupport", isSupport);
}
};
WebP.isSupport = function(cb) {
if (!cb) return;
if (!window.chrome && !window.opera) return WebP._cb(false, cb);
if (window.localStorage && window.localStorage.getItem("webpsupport") !== null) {
var val = window.localStorage.getItem("webpsupport");
WebP._cb(val === "true", cb);
return;
}
var img = new Image();
img.src = "data:image/webp;base64,UklGRjoAAABXRUJQVlA4IC4AAACyAgCdASoCAAIALmk0mk0iIiIiIgBoSygABc6WWgAA/veff/0PP8bA//LwYAAA";
img.onload = img.onerror = function() {
WebP._cb(img.width === 2 && img.height === 2, cb);
};
};
WebP.run = function(cb) {
this.isSupport(function(isSupport) {
if (isSupport) cb();
});
};
})();
Có một cách để kiểm tra hỗ trợ webP ngay lập tức . Nó đồng bộ và chính xác, vì vậy không cần đợi cuộc gọi lại để hiển thị hình ảnh.
function testWebP = () => {
const canvas = typeof document === 'object' ?
document.createElement('canvas') : {};
canvas.width = canvas.height = 1;
return canvas.toDataURL ? canvas.toDataURL('image/webp').indexOf('image/webp') === 5 : false;
}
Phương pháp này đã cải thiện đáng kể thời gian hiển thị của tôi
image/webp
nhưng trả về false trong trường hợp này (nhưng hoạt động chính xác trên cả Safari và Chrome)
đây là một chức năng đơn giản với Promise dựa trên phản hồi của Pointy
let webpSupport = undefined // so we won't have to create the image multiple times
const webp1Px = 'data:image/webp;base64,UklGRjoAAABXRUJQVlA4IC4AAACyAgCdASoCAAIALmk0mk0iIiIiIgBoSygABc6WWgAA/veff/0PP8bA//LwYAAA'
function isWebpSupported () {
if (webpSupport !== undefined) {
return Promise.resolve(webpSupport)
}
return new Promise((resolve, _reject) => {
const img = new Image()
img.onload = () => {
webpSupport = !!(img.height > 0 && img.width > 0);
resolve(webpSupport)
}
img.onerror = () => {
webpSupport = false
resolve(webpSupport)
}
img.src = webp1Px
})
}
Phiên bản ngắn của tôi. Tôi đã sử dụng nó để cung cấp cho trình duyệt webP hoặc jpg / png.
Google ăn đứt điều này và iPhone cũ (f̶u̶c̶k̶i̶n̶g̶ ̶s̶h̶e̶e̶t̶ -safari) cũng hoạt động tốt!
function checkWebP(callback) {
var webP = new Image();
webP.onload = webP.onerror = function () {
callback(webP.height == 2);
};
webP.src = 'data:image/webp;base64,UklGRjoAAABXRUJQVlA4IC4AAACyAgCdASoCAAIALmk0mk0iIiIiIgBoSygABc6WWgAA/veff/0PP8bA//LwYAAA';
};
checkWebP(function(support) {
if(support) {
//Do what you whant =)
console.log('work webp');
}else{
//Do what you whant =)
console.log('not work, use jgp/png')
}
})
/* Here's a one-liner hack that works (without the use/need of any
externals...save bytes)...
Your CSS... */
body.no-webp .logo {
background-image: url('logo.png');
}
body.webp .logo {
background-image: url('logo.webp');
}
...
<body>
<!--
The following img tag is the *webp* support checker. I'd advise you use any
(small-sized) image that would be utilized on the current page eventually
(probably an image common to all your pages, maybe a logo) so that when
it'll be (really) used on the page, it'll be loaded from cache by the
browser instead of making another call to the server (for some other image
that won't be).
Sidebar: Using 'display: none' so it's not detected by screen readers and
so it's also not displayed (obviously). :)
-->
<img
style='display: none'
src='/path/to/low-sized-image.webp'
onload="this.parentNode.classList.add('webp')"
onerror="this.parentNode.classList.add('no-webp')"
/>
...
</body>
<!-- PS. It's my first answer on SO. Thank you. :) -->
Hình ảnh WebP với htaccess
Đặt phần sau vào .htaccess
tệp của bạn và hình ảnh jpg / png sẽ được thay thế bằng hình ảnh WebP nếu được tìm thấy trong cùng một thư mục.
<IfModule mod_rewrite.c>
RewriteEngine On
# Check if browser support WebP images
RewriteCond %{HTTP_ACCEPT} image/webp
# Check if WebP replacement image exists
RewriteCond %{DOCUMENT_ROOT}/$1.webp -f
# Serve WebP image instead
RewriteRule (.+)\.(jpe?g|png)$ $1.webp [T=image/webp,E=accept:1]
</IfModule>
<IfModule mod_headers.c>
Header append Vary Accept env=REDIRECT_accept
</IfModule>
<IfModule mod_mime.c>
AddType image/webp .webp
</IfModule>
Đọc thêm tại đây
JavaScript mở rộng Webp Phát hiện và Thay thế:
async function supportsWebp() {
if (!self.createImageBitmap) return false;
const webpData = 'data:image/webp;base64,UklGRh4AAABXRUJQVlA4TBEAAAAvAAAAAAfQ//73v/+BiOh/AAA=';
const blob = await fetch(webpData).then(r => r.blob());
return createImageBitmap(blob).then(() => true, () => false);
}
(async () => {
if(await supportsWebp()) {
console.log('webp does support');
}
else {
$('#banners .item').each(function(){
var src=$(this).find('img').attr('src');
src = src.replace(".webp", ".jpg");
$(this).find('img').attr('src',src);
});
console.log('webp does not support');
}
})();
Sử dụng câu trả lời của @ Pointy, câu trả lời này dành cho Angular 2+
:
import { Injectable } from '@angular/core';
import { Subject } from 'rxjs/Subject';
@Injectable()
export class ImageService {
private isWebpEnabledSource = new Subject<boolean>();
isWebpEnabledAnnounced$ = this.isWebpEnabledSource.asObservable();
isWebpEnabled() {
let webpImage = new Image();
webpImage.src = 'data:image/webp;base64,UklGRjIAAABXRUJQVlA4ICYAAACyAgCdASoCAAEALmk0mk0iIiIiIgBoSygABc6zbAAA/v56QAAAAA==';
webpImage.onload = () => {
if (webpImage.width === 2 && webpImage.height === 1) {
this.isWebpEnabledSource.next(true);
} else {
this.isWebpEnabledSource.next(false);
}
}
}
}
Phiên bản cải tiến để xử lý Firefox dựa trên Rui Marques. Tôi đã thêm quá trình quét các chuỗi khác nhau dựa trên nhận xét cho câu trả lời đó.
Nếu cải tiến này được cộng đồng chấp nhận, nó nên được chỉnh sửa theo câu trả lời đó.
function canUseWebP()
{
var elem = document.createElement('canvas');
if (!!(elem.getContext && elem.getContext('2d')))
{
var testString = (!(window.mozInnerScreenX == null)) ? 'png' : 'webp';
// was able or not to get WebP representation
return elem.toDataURL('image/webp').indexOf('data:image/' + testString) == 0;
}
// very old browser like IE 8, canvas not supported
return false;
}