ฉันจะตรวจสอบการรองรับ WebP ผ่าน Javascript ได้อย่างไร ฉันต้องการใช้การตรวจจับคุณสมบัติมากกว่าการตรวจจับเบราว์เซอร์หากเป็นไปได้ แต่ฉันหาวิธีทำไม่ได้ Modernizr ( www.modernizr.com ) ไม่ได้ตรวจสอบ
ฉันจะตรวจสอบการรองรับ WebP ผ่าน Javascript ได้อย่างไร ฉันต้องการใช้การตรวจจับคุณสมบัติมากกว่าการตรวจจับเบราว์เซอร์หากเป็นไปได้ แต่ฉันหาวิธีทำไม่ได้ Modernizr ( www.modernizr.com ) ไม่ได้ตรวจสอบ
คำตอบ:
นี่คือวิธีแก้ปัญหาของฉัน - ใช้เวลาประมาณ 6ms และฉันกำลังพิจารณาว่า WebP เป็นเพียงฟีเจอร์สำหรับเบราว์เซอร์สมัยใหม่เท่านั้น ใช้วิธีการอื่นโดยใช้ฟังก์ชั่น canvas.toDataUrl () แทนรูปภาพเป็นวิธีตรวจจับคุณสมบัติ:
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;
ฉันคิดว่าสิ่งนี้อาจใช้ได้:
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';
})();
ใน Firefox และ IE จะไม่มีการเรียกตัวจัดการ "onload" เลยหากไม่สามารถเข้าใจภาพได้และจะเรียก "onerror" แทน
คุณไม่ได้พูดถึง jQuery แต่เป็นตัวอย่างวิธีจัดการกับลักษณะอะซิงโครนัสของการตรวจสอบนั้นคุณสามารถส่งคืนวัตถุ 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();
}
จากนั้นคุณสามารถเขียน:
hasWebP().then(function() {
// ... code to take advantage of WebP ...
}, function() {
// ... code to deal with the lack of WebP ...
});
ตรวจสอบการที่สูงขึ้น: http://jsfiddle.net/JMzj2/29/ ภาพนี้โหลดภาพจาก URL ข้อมูลและตรวจสอบว่าโหลดสำเร็จหรือไม่ เนื่องจากตอนนี้ WebP รองรับรูปภาพแบบไม่สูญเสียข้อมูลแล้วคุณสามารถตรวจสอบได้ว่าเบราว์เซอร์ปัจจุบันรองรับ WebP ที่สูญหายหรือไม่ (หมายเหตุ: สิ่งนี้จะตรวจสอบการรองรับ URL ข้อมูลโดยปริยายด้วย)
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");
});
โซลูชันที่ต้องการใน 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"
เป็นสิ่งสำคัญเพื่อให้เบราว์เซอร์ข้ามไปหากไม่ทราบรูปแบบ!
วิธีอย่างเป็นทางการโดย Google:
เนื่องจากเบราว์เซอร์รุ่นเก่าบางตัวมีการรองรับ webp บางส่วนดังนั้นจึงเป็นการดีกว่าที่จะระบุคุณลักษณะ webp ที่คุณพยายามใช้และตรวจพบคุณลักษณะเฉพาะนี้ให้เจาะจงมากขึ้นและนี่คือคำแนะนำอย่างเป็นทางการของ Googleสำหรับวิธีตรวจหาคุณลักษณะ webp ที่เฉพาะเจาะจง:
// 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];
}
ตัวอย่างการใช้งาน:
check_webp_feature('lossy', function (feature, isSupported) {
if (isSupported) {
// webp is supported,
// you can cache the result here if you want
}
});
โปรดทราบว่าภาพโหลดไม่ปิดกั้นและไม่ตรงกัน ซึ่งหมายความว่าควรใส่รหัสใด ๆ ที่ขึ้นอยู่กับการสนับสนุน WebP ในฟังก์ชันเรียกกลับ
โปรดทราบว่าโซลูชันซิงโครนัสอื่น ๆ จะทำงานร่วมกับFirefox 65ได้ไม่ดี
นี่เป็นคำถามเก่า แต่ Modernizr รองรับการตรวจจับ Webp แล้ว
http://modernizr.com/download/
มองหาimg-webp
ภายใต้การตรวจจับที่ไม่ใช่คอร์
นี่คือคำตอบของ James Westgate ใน 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: เท็จ
FF65: จริง
Chrome: จริง
ฉันชอบคำตอบแบบซิงโครนัสจาก Rui Marques แต่น่าเสียดายที่ FF65 ยังคงส่งคืนเท็จแม้ว่าจะมีความสามารถในการแสดง WebP
นี่คือรหัสโดยไม่ต้องขอภาพ อัปเดตด้วยซอใหม่ของ 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 ใช้การตรวจจับการสนับสนุน WebP ที่ชาญฉลาดขึ้นโดยไม่ต้องใช้ภาพภายนอก: http://webpjs.appspot.com/
ฉันพบว่าคุณสมบัติการสนับสนุน webp ตรวจจับต้องใช้ 300 + ms เมื่อหน้า JavaScript หนัก ดังนั้นฉันจึงเขียนสคริปต์ที่มีคุณสมบัติการแคช:
จะตรวจพบเพียงครั้งเดียวเมื่อผู้ใช้เข้าถึงเพจครั้งแรก
/**
* @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();
});
};
})();
/* 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. :) -->
ไม่มีทางที่จะทดสอบการสนับสนุน WebP เป็นทันที มันซิงค์และถูกต้องดังนั้นจึงไม่จำเป็นต้องรอให้โทรกลับเพื่อแสดงภาพ
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;
}
วิธีนี้ช่วยเพิ่มเวลาในการแสดงผลของฉันอย่างมาก
image/webp
แต่ส่งคืนเท็จในกรณีนี้ (แต่ใช้ได้ทั้งบน Safari และ Chrome อย่างถูกต้อง)
นี่คือฟังก์ชั่นง่ายๆที่มี Promise ตามการตอบสนองของ 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
})
}
ฉบับย่อของฉัน ฉันใช้มันเพื่อให้ webP เบราว์เซอร์หรือ jpg / png
Google กินสิ่งนี้และ iPhone รุ่นเก่า (f̶u̶c̶k̶i̶n̶g̶̶s̶h̶e̶e̶t̶ -safari) ก็ใช้ได้ดีเช่นกัน!
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')
}
})
ภาพ WebP ด้วย htaccess
วางสิ่งต่อไปนี้ใน.htaccess
ไฟล์ของคุณและรูปภาพ jpg / png จะถูกแทนที่ด้วยภาพ WebP หากพบในโฟลเดอร์เดียวกัน
<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>
อ่านเพิ่มเติมที่นี่
ส่วนขยาย Webp ตรวจจับและเปลี่ยน JavaScript:
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');
}
})();
เวอร์ชันปรับปรุงเพื่อรองรับ Firefox ที่ใช้ Rui Marques ฉันเพิ่มการสแกนสำหรับสตริงต่างๆตามความคิดเห็นของคำตอบนั้น
หากการปรับปรุงนี้ได้รับการยอมรับจากชุมชนควรแก้ไขในคำตอบนั้น
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;
}
การใช้คำตอบของ @ Pointy นี้มีไว้สำหรับ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);
}
}
}
}