检测不支持HTML5 <canvas>的最佳方法


139

处理浏览器不支持HTML5 <canvas>标签的情况的标准方法是嵌入一些后备内容,例如:

<canvas>Your browser doesn't support "canvas".</canvas>

但是页面的其余部分保持不变,这可能是不合适的或令人误解的。我想要某种检测画布不受支持的方式,以便可以相应地显示页面的其余部分。你会推荐什么?

Answers:


217

这是Modernizr以及基本上所有其他执行画布工作的库中使用的技术:

function isCanvasSupported(){
  var elem = document.createElement('canvas');
  return !!(elem.getContext && elem.getContext('2d'));
}

由于您的问题是在支持的情况下用于检测,因此我建议像这样使用它:

if (!isCanvasSupported()){ ...

14
为什么双重否定(!!)代表?

16
如果Canvas不存在,elem.getContext == undefined!undefined = true!true = false,因此这使我们返回布尔值,而不是返回未定义或上下文。
Rich Bradshaw

1
@ 2astalavista双负号(!!)就像强制转换。它将true或false语句转换为布尔值。例如:var i = 0。我计算为假,但typeof我返回“数字”。typeof !! i返回“布尔值”。
User2 2014年

另一种“转换”为布尔值的方法是:(undefined ? true : false尽管有点冗长)。
vcapra1 2014年

1
我应该注意,有不同类型的画布支持。早期的浏览器实现不支持toDataURL。Opera Mini仅支持基本的画布渲染,而没有文本API支持。Opera Mini的,可以排除这种方式,只是交叉引用。
hexalys

103

有两种流行的方法可以检测浏览器中的画布支持:

  1. 马特(Matt)建议检查的存在getContext,并由Modernizr库以类似方式使用:

    var canvasSupported = !!document.createElement("canvas").getContext;
  2. 检查HTMLCanvasElement接口的存在,如WebIDLHTML规范所定义。IE 9团队的博客文章中也推荐了这种方法。

    var canvasSupported = !!window.HTMLCanvasElement;

我的建议是后者的一种变体(请参见附加说明),原因如下:

  • 每个已知的支持canvas的浏览器(包括IE 9)都实现了此接口;
  • 简洁明了,立即可见代码在做什么。
  • 在所有浏览器中,该getContext方法的速度明显慢,因为它涉及创建HTML元素。当您需要压缩尽可能多的性能时(例如在类似Modernizr的库中),这不是理想的选择。

使用第一种方法没有明显的好处。两种方法都可以被欺骗,但这不太可能偶然发生。

补充笔记

仍然有必要检查2D上下文是否可以检索。据报道,某些移动浏览器可以为上述两项检查返回true,但是null.getContext('2d')。这就是为什么Modernizr还检查的结果的原因.getContext('2d')。但是,WebIDL和HTML再次为我们提供了另一个更好,更快的选择:

var canvas2DSupported = !!window.CanvasRenderingContext2D;

请注意,我们可以完全跳过对canvas元素的检查,而直接检查2D渲染支持。该CanvasRenderingContext2D接口也是HTML规范的一部分。

必须使用这种getContext方法来检测WebGL的支持,因为即使浏览器可能支持WebGLRenderingContextgetContext()但如果由于驱动程序问题而导致浏览器无法与GPU交互并且没有软件实现,则浏览器可能会返回null。在这种情况下,首先检查接口可让您跳过以下检查getContext

var cvsEl, ctx;
if (!window.WebGLRenderingContext)
    window.location = "http://get.webgl.org";
else {
    cvsEl = document.createElement("canvas");
    ctx = cvsEl.getContext("webgl") || cvsEl.getContext("experimental-webgl");

    if (!ctx) {
        // Browser supports WebGL, but cannot create the context
    }
}

性能比较

getContext方法的性能在Firefox 11和Opera 11中降低了85-90%,在Chromium 18中降低了约55%。

    简单比较表,单击可在浏览器中运行测试


10
诺基亚S60和黑莓风暴是其中一些会在建议的2D画布检测中误报的设备。不幸的是,移动设备变得非常笨拙,供应商不遵守规则。:(所以我们更完整的(即更慢)的测试结束,以确保准确的结果。
保罗爱尔兰

@Paul:很有意思,我测试了BlackBerry Storm模拟器,它们都返回false给您的示例和我的示例,看来它们不提供CanvasRenderingContext2D界面。到目前为止,我还无法测试S60,但我仍然很好奇,可能很快就会测试。
Andy E

1
这很有趣,但是只要测试低于100毫秒,就可以了吗?我想他们无论如何都比那快得多。如果您记住要对此进行测试的功能,则只需支付一次费用。
Drew Noakes

1
我运行了您的基准,甚至“慢”方法也可以每秒完成约800,000次。同样,如果结果被缓存,则决定在其采用何种方法,应基于稳健性,而不是性能(假设有一个在稳健性的差异。)
德鲁诺克斯

@DrewNoakes:是的,您应该始终追求兼容性而不是速度。我的论点是,基于Paul在他的评论中提到的至少一个有问题的浏览器中的测试,我驳斥了Paul的兼容性声明。我一直无法测试其他浏览器,但我仍然不相信存在问题。您应该始终致力于在不牺牲兼容性的情况下获得最佳性能。我不是在谈论微优化,但是如果您正在运行数百个测试,而它们却都未优化,那么可以,它会有所作为。
Andy E

13

getContext创建画布对象时,通常会进行检查。

(function () {
    var canvas = document.createElement('canvas'), context;
    if (!canvas.getContext) {
        // not supported
        return;
    }

    canvas.width = 800;
    canvas.height = 600;
    context = canvas.getContext('2d');
    document.body.appendChild(canvas);
}());

如果支持,则可以继续画布设置并将其添加到DOM。这是“ 渐进增强”的简单示例,我(个人)更喜欢“优雅降级”。


那是, context第二行的迷路吗?
brainjam 2010年

7
@brainjam-不,我在代码结尾处使用了该变量。我尝试遵循JSLint的 “建议”(在这种情况下。var每个函数只有1条语句)。
马特2010年

6

为什么不尝试 modernizr?这是一个提供检测功能的JS库。

引用:

您是否曾经想过在CSS中进行if语句以获取诸如边框半径之类的酷功能?好吧,有了Modernizr,您就可以做到!


2
我们在modernizr中使用的测试是:return !!document.createElement('canvas').getContext 这绝对是最好的测试方法。
保罗·爱尔兰

4
Modernizr是一个有用的库,但是仅仅为了检测画布支持而引入整个库可能会有点浪费。如果您还需要检测其他功能,则建议使用。
丹尼尔·卡西迪

5
try {
    document.createElement("canvas").getContext("2d");
    alert("HTML5 Canvas is supported in your browser.");
} catch (e) {
    alert("HTML5 Canvas is not supported in your browser.");
}

1

这里可能有一个陷阱-一些客户端不支持所有的 canvas方法。

var hascanvas= (function(){
    var dc= document.createElement('canvas');
    if(!dc.getContext) return 0;
    var c= dc.getContext('2d');
    return typeof c.fillText== 'function'? 2: 1;
})();

alert(hascanvas)


0

如果要获取画布的上下文,则最好将其用作测试:

var canvas = document.getElementById('canvas');
var context = (canvas.getContext?canvas.getContext('2d'):undefined);
if(!!context){
  /*some code goes here, and you can use 'context', it is already defined*/
}else{
  /*oof, no canvas support :(*/
}
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.