Como posso detectar suporte para WebP via Javascript? Gostaria de usar a detecção de recursos em vez da detecção de navegador, se possível, mas não consigo encontrar uma maneira de fazer isso. Modernizr ( www.modernizr.com ) não verifica.
javascript
html
image
webp
Dieki
fonte
fonte
Respostas:
Esta é a minha solução - está demorando cerca de 6 ms e estou considerando que o WebP é apenas um recurso para um navegador moderno. Usa uma abordagem diferente usando a função canvas.toDataUrl () em vez da imagem como forma de detectar o recurso:
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; } }
fonte
webp = e => document.createElement('canvas').toDataURL('image/webp').indexOf('data:image/webp') == 0;
Acho que algo assim pode funcionar:
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'; })();
No Firefox e no IE, o manipulador "onload" simplesmente não será chamado se a imagem não puder ser entendida e, em vez disso, o "onerror" será chamado.
Você não mencionou jQuery, mas como um exemplo de como lidar com a natureza assíncrona dessa verificação, você pode retornar um objeto 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(); }
Então você pode escrever:
hasWebP().then(function() { // ... code to take advantage of WebP ... }, function() { // ... code to deal with the lack of WebP ... });
Aqui está um exemplo jsfiddle.
Um verificador mais avançado: http://jsfiddle.net/JMzj2/29/ . Este carrega imagens de um URL de dados e verifica se ele carrega com sucesso. Como o WebP agora também oferece suporte a imagens sem perdas, você pode verificar se o navegador atual oferece suporte apenas para WebP com perdas ou também WebP sem perdas. (Observação: isso também verifica implicitamente o suporte a URL de dados.)
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"); });
fonte
Solução preferida em
HTML5
<picture> <source srcset="/path/to/image.webp" type="image/webp"> <img src="/path/to/image.jpg" alt="insert alt text here"> </picture>
Wiki no W3C
fonte
type="image/webp"
é fundamental para o navegador ignorá-lo se o formato for desconhecido!Forma oficial do Google:
Como alguns navegadores antigos têm suporte parcial para webp , é melhor ser mais específico qual recurso webp você está tentando usar e detectar esse recurso específico, e aqui está a recomendação oficial do Google sobre como detectar um recurso webp específico:
// 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]; }
Exemplo de uso:
check_webp_feature('lossy', function (feature, isSupported) { if (isSupported) { // webp is supported, // you can cache the result here if you want } });
Observe que o carregamento da imagem não é bloqueador e é assíncrono . Isso significa que qualquer código que dependa do suporte WebP deve ser preferencialmente colocado na função de retorno de chamada.
Observe também que outras soluções síncronas não funcionarão bem com o Firefox 65
fonte
Essa é uma questão antiga, mas a Modernizr agora oferece suporte para detecção de Webp.
http://modernizr.com/download/
Procure em
img-webp
Detecções não essenciais.fonte
Aqui está uma versão da resposta de James Westgate em 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: falso
FF65: verdadeiro
Chrome: verdadeiro
Adoro a resposta síncrona do Rui Marques, mas infelizmente FF65 continua a ser falso apesar de poder apresentar WebP.
fonte
Aqui está o código sem precisar solicitar uma imagem. Atualizado com o novo violino do 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'; });
fonte
WebPJS usa detecção de suporte WebP mais inteligente sem a necessidade de imagens externas: http://webpjs.appspot.com/
fonte
Descobri que a detecção de recurso de suporte webp requer 300 + ms quando a página tem muito JavaScript. Então, escrevi um script com recursos de cache:
Ele detectará apenas uma vez quando o usuário acessar a página pela primeira vez.
/** * @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(); }); }; })();
fonte
/* 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. :) -->
fonte
Existe uma maneira de testar o suporte webP instantaneamente . É sincronizado e preciso, portanto, não há necessidade de esperar por um retorno de chamada para renderizar as imagens.
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; }
Este método melhorou meu tempo de renderização dramaticamente
fonte
image/webp
mas retorna falso neste caso (mas funciona no Safari e no Chrome corretamente)aqui está uma função simples com Promise baseada na resposta de 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 }) }
fonte
Minha versão curta. Eu o usei para fornecer ao navegador webP ou jpg / png.
O Google come isso, e o iphone antigo (f̶u̶c̶k̶i̶n̶g̶ ̶s̶h̶e̶e̶t̶ -safari) também funciona muito bem!
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') } })
fonte
Imagens WebP com htaccess
Coloque o seguinte em seu
.htaccess
arquivo e as imagens jpg / png serão substituídas por imagens WebP se encontradas na mesma pasta.<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>
Leia mais aqui
fonte
Extensão Webp Detectar e substituir 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'); } })();
fonte
Versão melhorada para lidar com Firefox baseada em Rui Marques. Eu adicionei a varredura para as diferentes strings com base nos comentários a essa resposta.
Se essa melhoria for aceita pela comunidade, ela deve ser editada nessa resposta.
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; }
fonte
Usando a resposta de @ 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); } } } }
fonte