web-dev-qa-db-fra.com

Détection du support WebP

Comment détecter le support de WebP via Javascript? Si possible, j'aimerais utiliser la détection de fonctionnalités plutôt que la détection de navigateur, mais je ne trouve pas le moyen de le faire. Modernizr ( www.modernizr.com ) ne le vérifie pas.

53
snostorm

Je pense que quelque chose comme ceci pourrait fonctionner:

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';
})();

Dans Firefox et IE, le gestionnaire "onload" ne sera tout simplement pas appelé si l'image ne peut pas être comprise, et "onerror" est appelé à la place.

Vous n'avez pas mentionné jQuery, mais vous pouvez, comme exemple de gestion de la nature asynchrone de cette vérification, renvoyer un objet "différé" jQuery:

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();
}

Ensuite, vous pourriez écrire:

hasWebP().then(function() {
  // ... code to take advantage of WebP ...
}, function() {
  // ... code to deal with the lack of WebP ...
});

Voici un exemple jsfiddle.


Un vérificateur plus avancé: http://jsfiddle.net/JMzj2/29/ . Celui-ci charge les images à partir d'une URL de données et vérifie si le chargement est réussi. Puisque WebP prend désormais également en charge les images sans perte, vous pouvez vérifier si le navigateur actuel prend en charge uniquement WebP avec perte ou également WebP sans perte. (Remarque: cette option vérifie également la prise en charge des URL de données.)

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");
});
47
Pointy

Ceci est ma solution - prend environ 6 ms et je considère que WebP n’est qu’une fonctionnalité pour un navigateur moderne. Utilise une approche différente en utilisant la fonction canvas.toDataUrl () au lieu d’image pour détecter l’entité:

function canUseWebP() {
    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;
    }

    // very old browser like IE 8, canvas not supported
    return false;
}
57
Rui Marques

C'est une vieille question, mais Modernizr prend désormais en charge la détection Webp.

http://modernizr.com/download/

Recherchez img-webp sous Détection non principale.

11
Jake Wilson

Solution préférée 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 sur le W3C

9
Andrei Krasutski

Voici du code sans avoir à demander une image. Mis à jour avec le nouveau violon 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';
});
5
James Westgate

WebPJS utilise une détection plus intelligente du support WebP, sans images externes requises: http://webpjs.appspot.com/

5
unxed

J'ai trouvé que la fonctionnalité de support Webp détecte nécessite plus de 300 ms lorsque la page est trop chargée en JavaScript. Alors j'ai écrit un script avec des fonctionnalités de cache:

  • cache de script
  • cache de stockage local

Il ne détectera qu'une fois le premier accès de l'utilisateur à la page.

/**
 * @fileOverview WebP Support Detect.
 * @author ChenCheng<[email protected]>
 */
(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();
    });
  };

})();
3
sorrycc

Voici une version de la réponse de James Westgate dans 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 = function () {
            res(webP.height === 2);
        };        
    })
};

testWebP().then(hasWebP => console.log(hasWebP));

FF64: faux

FF65: vrai

Chrome: vrai

J'aime la réponse synchrone de Rui Marques, mais malheureusement, FF65 renvoie toujours la valeur false même si elle est capable d'afficher WebP.

2
RoccoB

Images WebP avec htaccess

Placez les éléments suivants dans votre fichier .htaccess et les images jpg/png seront remplacées par des images WebP si elles se trouvent dans le même dossier.

<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>

En savoir plus ici

1
Andrei Krasutski

voici une fonction simple avec Promise basée sur la réponse 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
  })
}
1
Liron Navon

Il existe un moyen de tester le support WebP instantanément . Il est synchronisé et précis, il n’est donc pas nécessaire d’attendre un rappel pour restituer les images.

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;
}

Cette méthode a considérablement amélioré mon temps de rendu

1
Guy Sopher

Webp extension détecter et remplacer 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');
  }
})();
1
Limitless isa

Utiliser la réponse de @ Pointy pour 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);
            }
        }
    }
}
1
Serj Sagan

Nous pouvons utiliser ce JS pour quel navigateur détecte l’extension webp. nous pouvons obtenir la classe en balise HTML. En fonction de la classe, nous pouvons définir une image d'arrière-plan.

<html lang="en-US" class="webp webp-alpha webp-animation webp-lossless"></html>

Si ne supporte pas le navigateur

<html lang="en-US" class="no-webp"></html>

JS est ici.

!function(e,A,n){var o=[],a=[],t={_version:"3.6.0",_config:{classPrefix:"",enableClasses:!0,enableJSClass:!0,usePrefixes:!0},_q:[],on:function(e,A){var n=this;setTimeout(function(){A(n[e])},0)},addTest:function(e,A,n){a.Push({name:e,fn:A,options:n})},addAsyncTest:function(e){a.Push({name:null,fn:e})}},i=function(){};function s(e,A){return typeof e===A}i.prototype=t,i=new i;var l,r,f=A.documentElement,u="svg"===f.nodeName.toLowerCase();function c(e){var A=f.className,n=i._config.classPrefix||"";if(u&&(A=A.baseVal),i._config.enableJSClass){var o=new RegExp("(^|\\s)"+n+"no-js(\\s|$)");A=A.replace(o,"$1"+n+"js$2")}i._config.enableClasses&&(A+=" "+n+e.join(" "+n),u?f.className.baseVal=A:f.className=A)}function p(e,A){if("object"==typeof e)for(var n in e)l(e,n)&&p(n,e[n]);else{var o=(e=e.toLowerCase()).split("."),a=i[o[0]];if(2==o.length&&(a=a[o[1]]),void 0!==a)return i;A="function"==typeof A?A():A,1==o.length?i[o[0]]=A:(!i[o[0]]||i[o[0]]instanceof Boolean||(i[o[0]]=new Boolean(i[o[0]])),i[o[0]][o[1]]=A),c([(A&&0!=A?"":"no-")+o.join("-")]),i._trigger(e,A)}return i}l=s(r={}.hasOwnProperty,"undefined")||s(r.call,"undefined")?function(e,A){return A in e&&s(e.constructor.prototype[A],"undefined")}:function(e,A){return r.call(e,A)},t._l={},t.on=function(e,A){this._l[e]||(this._l[e]=[]),this._l[e].Push(A),i.hasOwnProperty(e)&&setTimeout(function(){i._trigger(e,i[e])},0)},t._trigger=function(e,A){if(this._l[e]){var n=this._l[e];setTimeout(function(){var e;for(e=0;e<n.length;e++)(0,n[e])(A)},0),delete this._l[e]}},i._q.Push(function(){t.addTest=p}),i.addAsyncTest(function(){var e=[{uri:"data:image/webp;base64,UklGRiQAAABXRUJQVlA4IBgAAAAwAQCdASoBAAEAAwA0JaQAA3AA/vuUAAA=",name:"webp"},{uri:"data:image/webp;base64,UklGRkoAAABXRUJQVlA4WAoAAAAQAAAAAAAAAAAAQUxQSAwAAAABBxAR/Q9ERP8DAABWUDggGAAAADABAJ0BKgEAAQADADQlpAADcAD++/1QAA==",name:"webp.alpha"},{uri:"data:image/webp;base64,UklGRlIAAABXRUJQVlA4WAoAAAASAAAAAAAAAAAAQU5JTQYAAAD/////AABBTk1GJgAAAAAAAAAAAAAAAAAAAGQAAABWUDhMDQAAAC8AAAAQBxAREYiI/gcA",name:"webp.animation"},{uri:"data:image/webp;base64,UklGRh4AAABXRUJQVlA4TBEAAAAvAAAAAAfQ//73v/+BiOh/AAA=",name:"webp.lossless"}],A=e.shift();function n(e,A,n){var o=new Image;function a(A){var a=!(!A||"load"!==A.type)&&1==o.width;p(e,"webp"===e&&a?new Boolean(a):a),n&&n(A)}o.onerror=a,o.onload=a,o.src=A}n(A.name,A.uri,function(A){if(A&&"load"===A.type)for(var o=0;o<e.length;o++)n(e[o].name,e[o].uri)})}),function(){var e,A,n,t,l,r;for(var f in a)if(a.hasOwnProperty(f)){if(e=[],(A=a[f]).name&&(e.Push(A.name.toLowerCase()),A.options&&A.options.aliases&&A.options.aliases.length))for(n=0;n<A.options.aliases.length;n++)e.Push(A.options.aliases[n].toLowerCase());for(t=s(A.fn,"function")?A.fn():A.fn,l=0;l<e.length;l++)1===(r=e[l].split(".")).length?i[r[0]]=t:(!i[r[0]]||i[r[0]]instanceof Boolean||(i[r[0]]=new Boolean(i[r[0]])),i[r[0]][r[1]]=t),o.Push((t?"":"no-")+r.join("-"))}}(),c(o),delete t.addTest,delete t.addAsyncTest;for(var d=0;d<i._q.length;d++)i._q[d]();e.Modernizr=i}(window,document);
0
Niraj Kachhadiya

Ma version courte. Je l'ai utilisé pour donner au navigateur webP ou jpg/png.

Google mange ça, et le vieil iphone (f̶u̶ckin̶g̶ ̶s̶h̶e̶e̶t -safari) fonctionne très bien aussi!

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')
      }
      
})
0
Alexander Sanik

Étant donné que certains anciens navigateurs ont prise en charge partielle de webp _, il est donc préférable d'indiquer plus précisément la fonctionnalité WebP que vous essayez d'utiliser et de détecter cette fonctionnalité spécifique. Voici donc recommandation officielle de Google pour savoir comment détecter une fonctionnalité webp spécifique:

// check_webp_feature:
//   'feature' can be one of 'lossy', 'lossless', 'alpha' or 'animation'.
//   'callback(feature, result)' 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];
}

// example usage
check_webp_feature('lossy', function (feature, isSupported) {
    if (isSupported) {
        // web is supported
    }
});

Notez que le chargement d'image est non bloquant et asynchrone. Cela signifie que tout code dépendant de la prise en charge de WebP doit de préférence être placé dans la fonction de rappel.

Notez également que les autres solutions synchrones ne fonctionneront pas bien avec Firefox 65. 

0
AbdelHady