A melhor maneira de detectar que o <canvas> HTML5 não é suportado


139

A maneira padrão de lidar com situações em que o navegador não suporta a <canvas>tag HTML5 é incorporar algum conteúdo de fallback como:

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

Mas o restante da página permanece o mesmo, o que pode ser inapropriado ou enganoso. Gostaria de detectar uma forma de não suporte da tela para poder apresentar o restante da minha página de acordo. O que você recomendaria?

Respostas:


217

Esta é a técnica usada no Modernizr e basicamente em todas as outras bibliotecas que funcionam com canvas:

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

Desde a sua pergunta foi para detecção quando é não suportado, eu recomendo usá-lo assim:

if (!isCanvasSupported()){ ...

14
Por que a dupla negação (!!) representa?

16
Se o Canvas não estiver lá elem.getContext == undefined,. !undefined = true, e !true = false, portanto, isso nos permite retornar um bool, em vez de indefinido ou o contexto.
Ricos Bradshaw

1
@ 2astalavista O duplo negativo (!!) é como fundição. Transforma uma declaração truey ou falsey em um booleano. Por exemplo: var i = 0. avalia como false, mas typeof retorna "number". typeof !! i retorna "boolean".
usar o seguinte

Outra maneira de "converter" em booleano é: undefined ? true : false(embora um pouco mais demorado).
precisa saber é o seguinte

1
Devo observar que existem diferentes tipos de suporte de tela. As implementações anteriores do navegador não eram compatíveis toDataURL. E o Opera Mini suporta apenas renderização básica de tela sem suporte à API de texto . O Opera Mini pode ser excluído dessa maneira , apenas para referência cruzada.
Hexays

103

Existem dois métodos populares para detectar o suporte de tela nos navegadores:

  1. A sugestão de Matt de verificar a existência de getContext, também usada de maneira semelhante pela biblioteca Modernizr:

    var canvasSupported = !!document.createElement("canvas").getContext;
  2. Verificando a existência da HTMLCanvasElementinterface, conforme definido pelas especificações WebIDL e HTML . Essa abordagem também foi recomendada em um post da equipe do IE 9 .

    var canvasSupported = !!window.HTMLCanvasElement;

Minha recomendação é uma variação deste último (consulte as Notas adicionais ), por vários motivos:

  • Todo navegador que suporta telas - incluindo o IE 9 - implementa essa interface;
  • É mais conciso e instantaneamente óbvio o que o código está fazendo;
  • A getContextabordagem é significativamente mais lenta em todos os navegadores , porque envolve a criação de um elemento HTML. Isso não é ideal quando você precisa reduzir o máximo de desempenho possível (em uma biblioteca como Modernizr, por exemplo).

Não há benefícios visíveis no uso do primeiro método. Ambas as abordagens podem ser falsificadas, mas não é provável que isso aconteça por acidente.

Notas Adicionais

Ainda pode ser necessário verificar se um contexto 2D pode ser recuperado. Segundo informações, alguns navegadores móveis podem retornar true para as duas verificações acima, mas retornar nullpara .getContext('2d'). É por isso que Modernizr também verifica o resultado de .getContext('2d'). No entanto, WebIDL e HTML - novamente - nos oferecem outra opção melhor e mais rápida :

var canvas2DSupported = !!window.CanvasRenderingContext2D;

Observe que podemos pular a verificação do elemento canvas inteiramente e passar diretamente à verificação do suporte à renderização 2D. A CanvasRenderingContext2Dinterface também faz parte da especificação HTML.

Você deve usar a getContextabordagem para detectar o suporte WebGL porque, mesmo que o navegador suporte o WebGLRenderingContext, getContext()pode retornar nulo se o navegador não conseguir fazer interface com a GPU devido a problemas de driver e não houver implementação de software. Nesse caso, a verificação da interface primeiro permite que você pule a verificação de 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
    }
}

Comparação de desempenho

O desempenho da getContextabordagem é 85-90% mais lento no Firefox 11 e Opera 11 e cerca de 55% mais lento no Chromium 18.

    Tabela de comparação simples, clique para executar um teste no seu navegador


10
O Nokia S60 e o Blackberry Storm estão entre alguns dos dispositivos com falso positivo nas detecções de telas 2D propostas. Infelizmente, os dispositivos móveis ficam muito peludos e os fornecedores não seguem as regras. :( Então vamos acabar com testes mais completos (ou seja, mais lento) para garantir resultados precisos.
Paul Irish

@Paul: isso é interessante, eu testei os emuladores do BlackBerry Storm, todos eles retornados falsepara o seu exemplo e o meu, parece que eles não fornecem a CanvasRenderingContext2Dinterface. Ainda não consegui testar o S60, ainda estou muito curioso e posso fazê-lo em breve.
Andy E

1
Isso é interessante, mas contanto que o teste chegue a menos de cem milis, isso não é bom? Eu imagino que eles são todos muito mais rápidos do que isso de qualquer maneira. Se você memorizar uma função que testa isso, precisará pagar o custo apenas uma vez.
de Drew Noakes

1
Eu executei seu benchmark e até a abordagem "lenta" pode ser feita ~ 800.000 vezes por segundo. Novamente, se o resultado é armazenado em cache, em seguida, a decisão sobre qual abordagem para uso deve ser baseado na robustez, não desempenho (assumindo que há uma diferença em termos de robustez.)
de Drew Noakes

@ DrewNoakes: sim, você quase sempre deve procurar compatibilidade com velocidade. Meu argumento é que refuto as reivindicações de compatibilidade de Paul, com base em meus próprios testes em pelo menos um dos navegadores de problemas que ele mencionou em seu comentário. Não foi possível testar o outro navegador, mas não estou convencido de que haja um problema. Você deve sempre procurar obter o melhor desempenho possível, sem sacrificar a compatibilidade. Não estou falando de micro-otimização, mas se você estiver executando centenas de testes e todos estiverem otimizados, sim, isso pode fazer a diferença.
Andy E

13

Normalmente, procuro verificar getContextquando crio meu objeto de tela.

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

Se for suportado, você poderá continuar a configuração da tela e adicioná-la ao DOM. Este é um exemplo simples de Aperfeiçoamento Progressivo , que eu (pessoalmente) prefiro à Degradação Graciosa.


Isso está perdido , contextna segunda linha?
usar o seguinte comando

7
@brainjam - Não, eu uso essa variável perto do final do código. Eu tento seguir as 'recomendações' do JSLint (neste caso .. apenas 1 varinstrução por função).
30510 Matt

6

Por que não tentar modernizr ? É uma biblioteca JS que fornece capacidade de detecção.

Citar:

Você já desejou fazer declarações if no seu CSS para a disponibilidade de recursos interessantes como o raio da borda? Bem, com o Modernizr você pode conseguir exatamente isso!


2
O teste que usamos no modernizr é o seguinte: return !!document.createElement('canvas').getContext Essa é definitivamente a melhor maneira de testar.
Paul Irish

4
Modernizr é uma biblioteca útil, mas seria um desperdício extrair toda a biblioteca apenas para detectar o suporte à tela. Se você precisar detectar outros recursos também, recomendo.
Daniel Cassidy

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

Pode haver uma pegadinha aqui - alguns clientes não suportam todos os métodos de tela.

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

Você pode usar o script canisuse.js para detectar se o seu navegador suporta tela ou não

caniuse.canvas()

0

Se você quiser obter o contexto da sua tela, use-a como teste:

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 :(*/
}
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.