web-dev-qa-db-ja.com

WebPサポートの検出

Javascriptを介してWebPのサポートを検出するにはどうすればよいですか?可能であれば、ブラウザ検出ではなく機能検出を使用したいのですが、その方法は見つかりません。 Modernizr( www.modernizr.com )はチェックしません。

64
snostorm

私はこのような何かがうまくいくと思う:

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の「遅延」オブジェクトを返すことができます。

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

これはjsfiddleの例です。


より高度なチェッカー: http://jsfiddle.net/JMzj2/29/ 。これは、データURLから画像をロードし、正常にロードされるかどうかを確認します。 WebPはロスレス画像もサポートするようになったため、現在のブラウザが損失のある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");
});
51
Pointy

これが私の解決策です。約6ミリ秒かかります。WebPは最新のブラウザの機能に過ぎないと考えています。機能の検出方法として、画像の代わりにcanvas.toDataUrl()関数を使用する別のアプローチを使用します。

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;
}
75
Rui Marques

HTML5

<picture>
  <source srcset="/path/to/image.webp" type="image/webp">
  <img src="/path/to/image.jpg" alt="insert alt text here">
</picture>

W3CのWiki

19

これは古い質問ですが、ModernizrはWebp検出をサポートするようになりました。

http://modernizr.com/download/

探す img-webp [非コア検出]の下。

14
Jake Wilson

WebPJSは、外部イメージを必要としない、よりスマートなWebPサポート検出を使用します。 http://webpjs.appspot.com/

6
unxed

以下は、画像を要求する必要のないコードです。 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

ES6のJames Westgateの回答のバージョンを以下に示します。

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

FF65:true

Chrome:true

Rui Marquesからの同期回答は大好きですが、残念ながらFF65はWebPを表示する機能を持っているにもかかわらず、依然としてfalseを返します。

4
RoccoB

ページのJavaScriptが重い場合、webpサポート機能の検出には300ミリ秒以上かかることがわかりました。そこで、キャッシング機能を使用してスクリプトを作成しました。

  • スクリプトキャッシュ
  • localstorageキャッシュ

ユーザーが最初にページにアクセスしたときに検出されるのは1回だけです。

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

})();
4
sorrycc

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

// Example Usage
check_webp_feature('lossy', function (feature, isSupported) {
    if (isSupported) {
        // web is supported, 
        // you can cache the result here if you want
    }
});

イメージの読み込みは非ブロッキングであり、非同期であることに注意してください。これは、WebPサポートに依存するコードは、コールバック関数に配置することが望ましいことを意味します。

また、には他の同期ソリューションがFirefox 65ではうまく機能しないことに注意してください

4
AbdelHady

これは、Pointyの応答に基づくPromiseを使用した単純な関数です

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
  })
}
2
Liron Navon

htaccessを使用したWebP画像

以下を.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>

続きを読む こちら

1

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

この方法はレンダリング時間を劇的に改善しました

1
Guy Sopher

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

@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);
            }
        }
    }
}
1
Serj Sagan

ブラウザがwebp拡張機能を検出するこのJSを使用できます。 HTMLタグでクラスを取得できます。クラスに基づいて、背景画像を設定できます。

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

ブラウザをサポートしていない場合

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

JSはここにあります。

!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

私のショートバージョン。ブラウザ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')
      }
      
})
0
Alexander Sanik