¿Cómo puedo detectar la compatibilidad con WebP a través de Javascript? Me gustaría usar la detección de funciones en lugar de la detección del navegador si es posible, pero no puedo encontrar la manera de hacerlo. Modernizr ( www.modernizr.com ) no lo busca.
javascript
html
image
webp
snostorm
fuente
fuente
Respuestas:
Esta es mi solución: está tomando alrededor de 6 ms y estoy considerando que WebP es solo una característica para un navegador moderno. Utiliza un enfoque diferente usando la función canvas.toDataUrl () en lugar de la imagen como forma de detectar la característica:
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; } }
fuente
webp = e => document.createElement('canvas').toDataURL('image/webp').indexOf('data:image/webp') == 0;
Creo que algo como esto podría 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'; })();
En Firefox e IE, el controlador "onload" simplemente no se llamará en absoluto si la imagen no se puede entender, y en su lugar se llama "onerror".
No mencionaste jQuery, pero como ejemplo de cómo lidiar con la naturaleza asincrónica de esa verificación, podrías devolver un 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(); }
Entonces podrías escribir:
hasWebP().then(function() { // ... code to take advantage of WebP ... }, function() { // ... code to deal with the lack of WebP ... });
Aquí hay un ejemplo de jsfiddle.
Un verificador más avanzado: http://jsfiddle.net/JMzj2/29/ . Éste carga imágenes de una URL de datos y comprueba si se carga correctamente. Dado que WebP ahora también admite imágenes sin pérdida, puede verificar si el navegador actual solo admite WebP con pérdida o también WebP sin pérdida. (Nota: esto también comprueba implícitamente el soporte de URL de datos).
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"); });
fuente
Solución preferida en
HTML5
<picture> <source srcset="/path/to/image.webp" type="image/webp"> <img src="/path/to/image.jpg" alt="insert alt text here"> </picture>
Wiki en el W3C
fuente
type="image/webp"
es fundamental para que el navegador lo omita si tiene un formato desconocido.Forma oficial de Google:
Dado que algunos navegadores antiguos tienen soporte parcial para webp , es mejor ser más específico qué función webp está intentando usar y detectar esta función específica, y aquí está la recomendación oficial de Google sobre cómo detectar una función webp específica:
// 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]; }
Ejemplo de uso:
check_webp_feature('lossy', function (feature, isSupported) { if (isSupported) { // webp is supported, // you can cache the result here if you want } });
Tenga en cuenta que la carga de imágenes no se bloquea y es asincrónica . Esto significa que cualquier código que dependa del soporte de WebP debe colocarse preferiblemente en la función de devolución de llamada.
También tenga en cuenta que otras soluciones sincrónicas no funcionarán bien con Firefox 65
fuente
Esta es una pregunta antigua, pero Modernizr ahora admite la detección de Webp.
http://modernizr.com/download/
Busque en
img-webp
Detecciones no principales.fuente
Aquí hay una versión de la respuesta de James Westgate en 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: verdadero
Chrome: verdadero
Me encanta la respuesta sincrónica de Rui Marques, pero desafortunadamente FF65 todavía devuelve falso a pesar de tener la capacidad de mostrar WebP.
fuente
Aquí está el código sin tener que solicitar una imagen. Actualizado con el nuevo violín de 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'; });
fuente
WebPJS utiliza una detección de soporte WebP más inteligente sin necesidad de imágenes externas: http://webpjs.appspot.com/
fuente
Descubrí que la función de detección de soporte webp requiere más de 300 ms cuando la página tiene mucho JavaScript. Así que escribí un script con funciones de almacenamiento en caché:
Solo detectará una vez cuando el usuario acceda por primera vez a la página.
/** * @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(); }); }; })();
fuente
Hay una forma de probar la compatibilidad con webP al instante . Es sincronizado y preciso, por lo que no es necesario esperar una devolución de llamada para renderizar imágenes.
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 mejoró dramáticamente mi tiempo de renderizado
fuente
image/webp
pero devuelve falso en este caso (pero funciona correctamente en Safari y Chrome)aquí hay una función simple con Promise basada en la respuesta 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 }) }
fuente
Mi versión corta. Lo uso para dar navegador webP o jpg / png.
Google come esto, y el viejo iphone (f̶u̶c̶k̶i̶n̶g̶ ̶s̶h̶e̶e̶t̶ -safari) también funcionan muy bien.
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') } })
fuente
/* 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. :) -->
fuente
Imágenes WebP con htaccess
Coloque lo siguiente en su
.htaccess
archivo y las imágenes jpg / png serán reemplazadas por imágenes WebP si se encuentran en la misma carpeta.<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>
Leer más aquí
fuente
Extensión Webp Detectar y reemplazar 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'); } })();
fuente
Usando la respuesta de @ Pointy, esto es para
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); } } } }
fuente
Versión mejorada para manejar Firefox basada en Rui Marques. Agregué el escaneo de las diferentes cadenas en función de los comentarios a esa respuesta.
Si la comunidad acepta esta mejora, se debe editar en esa respuesta.
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; }
fuente