Jak mogę sprawdzić obsługę WebP za pomocą JavaScript? Chciałbym, jeśli to możliwe, użyć wykrywania funkcji zamiast wykrywania przeglądarki, ale nie mogę znaleźć sposobu, aby to zrobić. Modernizr ( www.modernizr.com ) nie sprawdza tego.
javascript
html
image
webp
dieki
źródło
źródło
Odpowiedzi:
To jest moje rozwiązanie - trwa około 6 ms i myślę, że WebP to tylko funkcja dla nowoczesnej przeglądarki. Używa innego podejścia, używając funkcji canvas.toDataUrl () zamiast obrazu jako sposobu wykrywania funkcji:
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; } }
źródło
webp = e => document.createElement('canvas').toDataURL('image/webp').indexOf('data:image/webp') == 0;
Myślę, że coś takiego może zadziałać:
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'; })();
W Firefoksie i IE, program obsługi "onload" nie zostanie w ogóle wywołany, jeśli obraz nie zostanie zrozumiany, a zamiast tego wywoływany jest "onerror".
Nie wspomniałeś o jQuery, ale jako przykład radzenia sobie z asynchroniczną naturą tego sprawdzenia możesz zwrócić obiekt 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(); }
Wtedy możesz napisać:
hasWebP().then(function() { // ... code to take advantage of WebP ... }, function() { // ... code to deal with the lack of WebP ... });
Oto przykład jsfiddle.
Bardziej zaawansowany kontroler: http://jsfiddle.net/JMzj2/29/ . Ten ładuje obrazy z adresu URL danych i sprawdza, czy ładuje się pomyślnie. Ponieważ WebP obsługuje teraz również bezstratne obrazy, możesz sprawdzić, czy aktualna przeglądarka obsługuje tylko stratny WebP, czy też bezstratny WebP. (Uwaga: to pośrednio sprawdza również obsługę adresów URL danych).
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"); });
źródło
Preferowane rozwiązanie w
HTML5
<picture> <source srcset="/path/to/image.webp" type="image/webp"> <img src="/path/to/image.jpg" alt="insert alt text here"> </picture>
Wiki na W3C
źródło
type="image/webp"
jest krytyczny, aby przeglądarka pominęła go w przypadku nieznanego formatu!Oficjalny sposób Google:
Ponieważ niektóre stare przeglądarki częściowo obsługują WebP , lepiej jest dokładniej określić, której funkcji WebP próbujesz użyć i wykryć tę konkretną funkcję. Oto oficjalne zalecenia Google dotyczące wykrywania określonej funkcji 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]; }
Przykładowe zastosowanie:
check_webp_feature('lossy', function (feature, isSupported) { if (isSupported) { // webp is supported, // you can cache the result here if you want } });
Zwróć uwagę, że ładowanie obrazu jest nieblokujące i asynchroniczne . Oznacza to, że jakikolwiek kod zależny od obsługi WebP powinien być umieszczony w funkcji wywołania zwrotnego.
Należy również pamiętać, że inne rozwiązania synchroniczne nie będą działać dobrze z przeglądarką Firefox 65
źródło
To stare pytanie, ale Modernizr obsługuje teraz wykrywanie Webp.
http://modernizr.com/download/
Poszukaj w
img-webp
obszarze Wykrywania niezwiązane z rdzeniem.źródło
Oto wersja odpowiedzi Jamesa Westgate'a w 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: fałsz
FF65: prawda
Chrome: prawda
Uwielbiam synchroniczną odpowiedź od Rui Marques, ale niestety FF65 nadal zwraca fałsz pomimo możliwości wyświetlania WebP.
źródło
Oto kod bez konieczności żądania obrazu. Zaktualizowano o nowe skrzypce qwerty.
http://jsfiddle.net/z6kH9/
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'; });
źródło
WebPJS wykorzystuje inteligentniejsze wykrywanie wsparcia WebP bez zewnętrznych obrazów: http://webpjs.appspot.com/
źródło
Zauważyłem, że funkcja wykrywania obsługi WebP wymaga 300 + ms, gdy strona jest obciążona JavaScript. Napisałem więc skrypt z funkcjami buforowania:
Wykrywa tylko raz, kiedy użytkownik po raz pierwszy uzyskuje dostęp do strony.
/** * @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(); }); }; })();
źródło
/* 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. :) -->
źródło
Istnieje sposób na natychmiastowe przetestowanie obsługi WebP . Jest zsynchronizowany i dokładny, więc nie trzeba czekać na wywołanie zwrotne, aby renderować obrazy.
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; }
Ta metoda znacznie poprawiła mój czas renderowania
źródło
image/webp
ale zwraca wartość false w tym przypadku (ale działa poprawnie zarówno w Safari, jak i Chrome)oto prosta funkcja z Obietnicą opartą na odpowiedzi 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 }) }
źródło
Moja krótka wersja. Używam go, aby nadać przeglądarce webP lub jpg / png.
Google je to, a stary iPhone (f̶u̶c̶k̶i̶n̶g̶ ̶s̶h̶e̶e̶t̶ -safari) też działa świetnie!
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') } })
źródło
Obrazy WebP z htaccess
Umieść następujące elementy w swoim
.htaccess
pliku, a obrazy jpg / png zostaną zastąpione obrazami WebP, jeśli zostaną znalezione w tym samym folderze.<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>
Przeczytaj więcej tutaj
źródło
Rozszerzenie Webp Wykryj i zamień 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'); } })();
źródło
Ulepszona wersja do obsługi Firefoksa oparta na Rui Marques. Dodałem skanowanie różnych ciągów na podstawie komentarzy do tej odpowiedzi.
Jeśli poprawienie zostanie zaakceptowane przez społeczność, należy je zredagować w odpowiedzi.
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; }
źródło
Używając odpowiedzi @ Pointy jest to dla
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); } } } }
źródło