【问题标题】:Detecting WebP support检测 WebP 支持
【发布时间】:2011-07-31 04:39:57
【问题描述】:

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

【问题讨论】:

  • 如果将这样的图像加载到 Image 元素中,然后在支持该格式的浏览器中检查宽度和高度,你会得到什么吗?跨度>
  • (我的意思是“Image object”,而不是元素;比如,“new Image()” ...)
  • 看起来不错。我可以通过这种方式获得“我确实支持 WebP”;但我无法得到“我不支持 WebP”。
  • 我在 WebP Google 群组上发布了一个类似的问题:What is Google's "official" recommendation for detecting WebP browser support?
  • @Simon_Weaver 这个问题和 cmets 都有几年的历史了。老问题很少以任何重要的方式“维护”;但是,您始终可以随意添加新答案。

标签: javascript html image webp


【解决方案1】:

//* WebP 支持检查 导入 { useState, useEffect } from "react";

const WebpSupportCheck = (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];
}

const IsWebpSupported = () => {
    const [state, setState] = useState()
    useEffect(() => {

        WebpSupportCheck('lossy', function (feature, isSupported) {
            if (isSupported) {
                setState(true)
            } else {
                setState(false)
            }
        })

    }, [state])
    return state
}

export default IsWebpSupported

【讨论】:

    【解决方案2】:

    上述解决方案在 safari 和 firefox 中可能不起作用。所以我开始寻找更强大的解决方案,并偶然发现了一个关于 webp 支持的优秀库:webp-hero 我们只能从这个库中获取 detectWebpSupport 函数:

    var __awaiter = (this && this.__awaiter) || function(thisArg, _arguments, P, generator) {
      function adopt(value) {
        return value instanceof P ? value : new P(function(resolve) {
          resolve(value);
        });
      }
      return new(P || (P = Promise))(function(resolve, reject) {
        function fulfilled(value) {
          try {
            step(generator.next(value));
          } catch (e) {
            reject(e);
          }
        }
    
        function rejected(value) {
          try {
            step(generator["throw"](value));
          } catch (e) {
            reject(e);
          }
        }
    
        function step(result) {
          result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected);
        }
        step((generator = generator.apply(thisArg, _arguments || [])).next());
      });
    };
    var __generator = (this && this.__generator) || function(thisArg, body) {
      var _ = {
          label: 0,
          sent: function() {
            if (t[0] & 1) throw t[1];
            return t[1];
          },
          trys: [],
          ops: []
        },
        f, y, t, g;
      return g = {
        next: verb(0),
        "throw": verb(1),
        "return": verb(2)
      }, typeof Symbol === "function" && (g[Symbol.iterator] = function() {
        return this;
      }), g;
    
      function verb(n) {
        return function(v) {
          return step([n, v]);
        };
      }
    
      function step(op) {
        if (f) throw new TypeError("Generator is already executing.");
        while (_) try {
          if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t;
          if (y = 0, t) op = [op[0] & 2, t.value];
          switch (op[0]) {
            case 0:
            case 1:
              t = op;
              break;
            case 4:
              _.label++;
              return {
                value: op[1],
                done: false
              };
            case 5:
              _.label++;
              y = op[1];
              op = [0];
              continue;
            case 7:
              op = _.ops.pop();
              _.trys.pop();
              continue;
            default:
              if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) {
                _ = 0;
                continue;
              }
              if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) {
                _.label = op[1];
                break;
              }
              if (op[0] === 6 && _.label < t[1]) {
                _.label = t[1];
                t = op;
                break;
              }
              if (t && _.label < t[2]) {
                _.label = t[2];
                _.ops.push(op);
                break;
              }
              if (t[2]) _.ops.pop();
              _.trys.pop();
              continue;
          }
          op = body.call(thisArg, _);
        } catch (e) {
          op = [6, e];
          y = 0;
        } finally {
          f = t = 0;
        }
        if (op[0] & 5) throw op[1];
        return {
          value: op[0] ? op[1] : void 0,
          done: true
        };
      }
    };
    
    function detectWebpSupport() {
      return __awaiter(this, void 0, void 0, function() {
        var testImageSources, testImage, results;
        return __generator(this, function(_a) {
          switch (_a.label) {
            case 0:
              testImageSources = [
                "data:image/webp;base64,UklGRjIAAABXRUJQVlA4ICYAAACyAgCdASoCAAEALmk0mk0iIiIiIgBoSygABc6zbAAA/v56QAAAAA==",
                "data:image/webp;base64,UklGRh4AAABXRUJQVlA4TBEAAAAvAQAAAAfQ//73v/+BiOh/AAA="
              ];
              testImage = function(src) {
                return new Promise(function(resolve, reject) {
                  var img = document.createElement("img");
                  img.onerror = function(error) {
                    return resolve(false);
                  };
                  img.onload = function() {
                    return resolve(true);
                  };
                  img.src = src;
                });
              };
              return [4 /*yield*/ , Promise.all(testImageSources.map(testImage))];
            case 1:
              results = _a.sent();
              return [2 /*return*/ , results.every(function(result) {
                return !!result;
              })];
          }
        });
      });
    }
    
    detectWebpSupport().then(d => console.log('does it support?', d))

    【讨论】:

      【解决方案3】:

      好消息。它适用于 Safari。

      document.addEventListener('DOMContentLoaded', function() {
        testWebP(document.body)
      })
      
      function testWebP(elem) {
        const webP = new Image();
        webP.src = 'data:image/webp;base64,UklGRjoAAABXRUJQVlA4IC4AAACyAgCdASoCAAIALmk0mk0iIiIiIgBoSygABc6WWgAA/veff/0PP8bA//LwYAAA';
        webP.onload = webP.onerror = function () {
          webP.height === 2 ? elem.classList.add('webp-true') : elem.classList.add('webp-false')
        }
        console.log(webP)
      }
      

      来源:https://gist.github.com/Protoff/d6643387f03d47b44b2d7c3cf7b3e0a0

      【讨论】:

        【解决方案4】:

        这是一种混合 HTML/Javascript 方法,可让您按优先顺序(您的偏好)确定支持的图像类型。在此示例中,它将返回浏览器中第一个支持的图像类型并检查 AVIF、WebP、JpegXL 和 JPG。

        <picture style="display:none;">
        <source type=image/avif srcset="data:image/avif;base64,AAAAFGZ0eXBhdmlmAAAAAG1pZjEAAACgbWV0YQAAAAAAAAAOcGl0bQAAAAAAAQAAAB5pbG9jAAAAAEQAAAEAAQAAAAEAAAC8AAAAGwAAACNpaW5mAAAAAAABAAAAFWluZmUCAAAAAAEAAGF2MDEAAAAARWlwcnAAAAAoaXBjbwAAABRpc3BlAAAAAAAAAAQAAAAEAAAADGF2MUOBAAAAAAAAFWlwbWEAAAAAAAAAAQABAgECAAAAI21kYXQSAAoIP8R8hAQ0BUAyDWeeUy0JG+QAACANEkA= 1x">
        <source type=image/webp srcset="data:image/webp;base64,UklGRiIAAABXRUJQVlA4IBYAAAAwAQCdASoBAAEADsD+JaQAA3AAAAAA 1x">
        <source type=image/jxl srcset="data:image/jxl;base64,/woAEBAJCAQBACwASxLFgoUJEP3D/wA= 1x">
        <img onload=console.log(this.currentSrc.substring(this.currentSrc.indexOf(':')+1,this.currentSrc.indexOf(';'))) src="data:image/jpg;base64,/9j/4AAQSkZJRgABAQIAHAAcAAD/2wBDAAMDAwMDAwMDAwMEBAQEBAYFBQUFBgkGBwYHBgkOCAoICAoIDgwPDAsMDwwWEQ8PERYZFRQVGR4bGx4mJCYyMkP/wgALCAABAAEBAREA/8QAFAABAAAAAAAAAAAAAAAAAAAACf/aAAgBAQAAAABU/wD/xAAUEAEAAAAAAAAAAAAAAAAAAAAA/9oACAEBAAE/AH//2Q==">
        </picture>
        

        您可以将日志功能替换为您需要的任何内容。

        这种方法的好处是:

        1. 您不必在 Javascript 中创建和查询一堆对象,因此效率很高
        2. 浏览器不必获取任何图像,它们是内联编码的,因此速度快且同步。您可以将其粘贴在任何地方,并在下一行中得到答案,而无需回调。
        3. 浏览器只会为支持的第一行创建图像结果,因此效率很高。
        4. 只需添加一行即可轻松添加未来的图像支持。
        5. 您可以根据您将在应用程序中使用的任何优先级对图像进行排序。
        6. 您可以通过修剪您不关心的图像类型将其转变为单独的测试。
        7. 即使不支持 PICTURE 元素但需要 currentSrc,这也应该可以工作,因此 IE11 将失败。在这种情况下,只需在 img 中测试 currentSrc,否则假定始终支持 JPG。

        编辑:删除进入示例的换行符,谢谢。

        【讨论】:

        • 在 avif 示例中有一个额外的换行符会破坏功能
        【解决方案5】:

        这是我的解决方案 - 大约需要 6 毫秒,我认为 WebP 只是现代浏览器的一项功能。使用不同的方法使用 canvas.toDataUrl() 函数而不是图像作为检测特征的方式:

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

        【讨论】:

        • 这应该是公认的答案,因为所有其他的都有延迟,因为指向网络资源或数据 URI
        • 简化版:webp = e =&gt; document.createElement('canvas').toDataURL('image/webp').indexOf('data:image/webp') == 0;
        • 这在支持显示 webp 的 Firefox 65 中不起作用,但不能从画布元素创建 webp 数据 url。
        • 喜欢这个,因为它是同步的,但是@carlcheel 是正确的。 FF 65(确实支持 webp)在这里仍然返回 false :-(
        • 如果它适用于 FF65 和 Edge18,这很棒。它们都支持 webp,但使用“data:image/png”序列化画布
        【解决方案6】:

        /* 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. :) -->

        【讨论】:

          【解决方案7】:

          Google 官方方式:

          由于一些旧浏览器有partial support for webp,因此最好更具体地说明您正在尝试使用哪个 webp 功能并检测此特定功能,这里是Google's official recommendation,了解如何检测特定 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];
          }
          

          示例用法:

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

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

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

          【讨论】:

            【解决方案8】:

            这是 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 = () => {
                        res(webP.height === 2);
                    };        
                })
            };
            
            testWebP().then(hasWebP => console.log(hasWebP));

            FF64: 错误

            FF65: 是的

            铬:是的

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

            【讨论】:

              【解决方案9】:

              基于 Rui Marques 处理 Firefox 的改进版本。我将基于 cmets 的不同字符串的扫描添加到该答案中。

              如果社区接受此改进,则应将其编辑到该答案中。

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

              【讨论】:

              • 尝试“elem.toDataURL('image/blablabla')”。这也返回 png,所以这不是 Firefox 解决方案。
              • 另外,未定义 testString。
              【解决方案10】:

              我的简短版本。我用它来给浏览器 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')
                    }
                    
              })

              【讨论】:

                【解决方案11】:

                这是无需请求图像的代码。更新了 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';
                });
                

                【讨论】:

                • 这对我来说完全被打破了。我把它分叉并让它工作:jsfiddle.net/z6kH9
                • 这适用于所有浏览器吗?我指的是Safari + FF65+中其他解决方案的问题。
                • 我认为这是最好的解决方案。仍然希望在旧浏览器和不支持 webp 的浏览器上看到测试。
                【解决方案12】:

                这是一个基于 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
                  })
                }
                

                【讨论】:

                • 虽然此代码可能会回答问题,但提供有关它如何和/或为什么解决问题的额外上下文将提高​​答案的长期价值。
                • 我认为这很清楚,我们尝试从base64字符串(1px宽和高)加载webp图像,如果我们正确加载它(调用onload)它是支持的,如果不是(调用onerror ) 不是,我只是把它包装在一个承诺中。
                【解决方案13】:

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

                【讨论】:

                  【解决方案14】:

                  使用@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);
                              }
                          }
                      }
                  }
                  

                  【讨论】:

                    【解决方案15】:

                    有一种方法可以立即测试 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;
                    }
                    

                    这种方法大大缩短了我的渲染时间

                    【讨论】:

                    • 在 Firefox 上不起作用...支持 image/webp 但在这种情况下返回 false(但在 Safari 和 Chrome 上都可以正常工作)
                    【解决方案16】:

                    HTML5中的首选解决方案

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

                    Wiki on W3C

                    【讨论】:

                    • 完美运行,type="image/webp" 对于格式未知时浏览器跳过它至关重要!
                    • 这个很好,但是对背景图片不起作用,而且如果你正在为网站改造webp,它需要修改你的html,这也意味着修改你的css中的所有地方引用 img 标签。
                    • 是的,这是解决问题的最佳方法。谢谢
                    • 所有支持webp的浏览器都支持图片元素吗?
                    • 虽然原生 HTML5 更可取,但大多数浏览器同时加载 JPG 和 WEBP,这会对下载时间产生负面影响。深入:smashingmagazine.com/2013/05/…
                    【解决方案17】:

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

                    阅读更多here

                    【讨论】:

                      【解决方案18】:

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

                      http://modernizr.com/download/

                      在非核心检测下查找img-webp

                      【讨论】:

                      • 来源很有用,看看他们做了什么github.com/Modernizr/Modernizr/blob/…
                      • 对我来说,它工作得非常可靠,它允许您使用 css 类 .webp 和 .no-webp 以获得更大的灵活性。
                      • 不得不使用一些自定义检查而不是modernizr,因为我找不到如何让它在像角度cli这样的现代堆栈上工作的方法(即使使用ngx-build-plus)
                      【解决方案19】:

                      我发现当页面的 JavaScript 很重时,webp 支持功能检测需要 300 多毫秒。所以我写了带有缓存功能的a script

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

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

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

                      【讨论】:

                        【解决方案20】:

                        我认为这样的事情可能会奏效:

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

                        那么你可以写:

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

                        Here is a jsfiddle example.


                        更高级的检查器: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");
                        });
                        

                        【讨论】:

                        • 太棒了!这适用于 FF、Chrome 和 IE 9。由于某种原因,它不适用于 IE8 或 IE7。
                        • 它在 IE7 中对我有用 - 试试我刚刚链接到答案末尾的 jsFiddle。
                        • 好吧,我原来的答案只有“onload”——我什至不知道 Image 对象有“onerror”:-)
                        • 哦,呵呵。我使用了 data: url 而不是图像,而 IE7 不支持。 :P
                        • 我刚刚意识到我可以让 IE8 与 data: urls 一起正常工作,并让 IE7 为其抛出错误;问题是他们不直接在javascript中支持它们。见:jsfiddle.net/HaLXz
                        【解决方案21】:

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

                        【讨论】:

                        • 他们用来加载文件的脚本可以在不实际使用文件的情况下使用。如果没有 WebP 支持,只需将内部替换为您想做的任何事情。
                        • 看起来他们正在使用数据 url,这就是我最终使用的。
                        猜你喜欢
                        • 2018-02-13
                        • 2019-12-13
                        • 2019-01-18
                        • 2013-08-12
                        • 2017-05-02
                        • 2012-01-01
                        • 2016-08-02
                        • 1970-01-01
                        • 1970-01-01
                        相关资源
                        最近更新 更多