检测WebP支持

sno*_*orm 68 html javascript image webp

如何通过Javascript检测对WebP的支持?如果可能的话,我想使用特征检测而不是浏览器检测,但我找不到这样做的方法.Modernizr(www.modernizr.com)没有检查它.

Rui*_*ues 82

这是我的解决方案 - 花费大约6毫秒,我正在考虑WebP只是现代浏览器的一项功能.使用canvas.toDataUrl()函数而不是image作为检测功能的方法使用不同的方法:

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;
}
Run Code Online (Sandbox Code Playgroud)

  • 这在支持显示webp但不支持从canvas元素创建webp数据URL的Firefox 65中不起作用. (16认同)
  • 这应该是可接受的答案,因为所有其他人都因为指向网络资源或数据URI而有延迟 (7认同)
  • 如果适用于FF65和Edge18,这将是很棒的。它们都支持webp,但是使用“ data:image / png”序列化画布 (6认同)
  • 简化版:`webp = e => document.createElement('canvas').toDataURL('image/webp').indexOf('data:image/webp')== 0;` (4认同)
  • 喜欢它,因为它是同步的,但是@carlcheel是正确的。FF 65(确实具有webp支持)在这里仍然返回false :-( (4认同)
  • 我看起来这只适用于 Chrome,这不是很有用...... (4认同)
  • 您应该将宽度和高度设置为 1px,否则 toDataURL 在 Chrome 和 Opera 中会很长。 (2认同)
  • 此解决方案不适用于Safari 12 (2认同)
  • 从 macOS BigSur 开始,它在 Safari 中添加了对 WebP 的支持,不幸的是,这在 Safari 中也不起作用,就像 FF65+ 的 `toDataURL('image/webp')` 生成 PNG 一样。 (2认同)
  • 这不适用于 Safari 14。Safari 14 支持 webp 但此函数返回 false (2认同)
  • @Rui - 你提到这大约需要 6 毫秒,你可以通过在编码之前将画布的宽度和高度设置为 1 将其降低到 1 毫秒。对于那些关心 safari-TMK 的人来说,某些仍然广泛使用的 safari 版本(15.?)具有 webp 支持,但对某些图像无法支持。它在后来的版本中得到了修复。目前,我一般都会在 Safari 上跳过 webp。 (2认同)
  • 它不适用于 safari,因为不支持 toDataUrl 类型“image/webp”。但 safari 可以显示 webp 图片。所以这个解决方案是错误的,不是答案。https://caniuse.com/mdn-api_htmlcanvaselement_todataurl_type_parameter_webp (2认同)

Poi*_*nty 52

我觉得这样的事情可能有用:

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';
})();
Run Code Online (Sandbox Code Playgroud)

在Firefox和IE中,如果无法理解图像,则根本不会调用"onload"处理程序,而是调用"onerror".

你没有提到jQuery,但作为如何处理该检查的异步性质的一个例子,你可以返回一个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();
}
Run Code Online (Sandbox Code Playgroud)

然后你可以写:

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

这是一个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");
});
Run Code Online (Sandbox Code Playgroud)

  • 我刚刚意识到我可以让 IE8 正常使用 data: urls,并让 IE7 抛出错误;问题是他们不直接在 JavaScript 中支持它们。请参阅:http://jsfiddle.net/HaLXz/ (3认同)

And*_*ski 24

优选的解决方案 HTML5

<picture>
  <source srcset="/path/to/image.webp" type="image/webp">
  <img src="/path/to/image.jpg" alt="insert alt text here">
</picture>
Run Code Online (Sandbox Code Playgroud)

维基百科W3C

  • 这很好,但它不适用于背景图像,并且如果您正在将 webp 改造到站点,并且它需要修改您的 html,这也意味着修改 css 中引用 img 标签的所有位置。 (9认同)
  • 尽管原生 HTML5 更可取,但大多数浏览器都会加载 JPG 和 WEBP,这会对下载时间产生负面影响。深入:https://www.smashingmagazine.com/2013/05/how-to-avoid-duplicate-downloads-in-responsive-images/ (3认同)
  • 完美运行,`type="image/webp"` 对于浏览器在未知格式时跳过它至关重要! (2认同)
  • 是的,这是解决问题的最佳方案。谢谢 (2认同)

Jak*_*son 15

这是一个老问题,但Modernizr现在支持Webp检测.

http://modernizr.com/download/

寻找img-webp非核心检测.

  • 来源对于了解他们做了什么很有用 https://github.com/Modernizr/Modernizr/blob/400db4043c22af98d46e1d2b9cbc5cb062791192/feature-detects/img/webp.js (3认同)

Jam*_*ate 9

这是代码,无需请求图像.更新了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';
});
Run Code Online (Sandbox Code Playgroud)

  • 这完全打破了我.我把它分叉并使其工作:http://jsfiddle.net/z6kH9/ (5认同)

Abd*_*ady 9

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) {
        // webp is supported, 
        // you can cache the result here if you want
    }
});
Run Code Online (Sandbox Code Playgroud)

请注意,图像加载是非阻塞且异步的。这意味着依赖于WebP支持的任何代码最好都应放在回调函数中。

另请注意,其他同步解决方案不适用于Firefox 65


小智 5

WebPJS使用更智能的WebP支持检测,无需外部图像:http://webpjs.appspot.com/


小智 5

我发现当页面是 JavaScript 时,webp 支持功能检测需要 300+ms。所以我写了一个带有缓存功能的脚本

  • 脚本缓存
  • 本地存储缓存

它只会在用户第一次访问页面时检测一次。

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

})();
Run Code Online (Sandbox Code Playgroud)


Roc*_*coB 5

这是James Westgate在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));
Run Code Online (Sandbox Code Playgroud)

FF64:错误

FF65:是的

铬:真

我很喜欢Rui Marques的同步回答,但是不幸的是,尽管FF65能够显示WebP,但仍然返回false。


Sun*_*sit 5

/* 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');
}
Run Code Online (Sandbox Code Playgroud)
...
<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. :) -->
Run Code Online (Sandbox Code Playgroud)