Il modo migliore per rilevare che HTML5 <canvas> non è supportato


139

Il modo standard di gestire situazioni in cui il browser non supporta il <canvas>tag HTML5 è incorporare alcuni contenuti di fallback come:

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

Ma il resto della pagina rimane lo stesso, il che potrebbe essere inappropriato o fuorviante. Vorrei un modo per rilevare il mancato supporto della tela in modo da poter presentare il resto della mia pagina di conseguenza. Cosa raccomanderesti?

Risposte:


217

Questa è la tecnica utilizzata in Modernizr e praticamente in tutte le altre librerie che eseguono lavori su tela:

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

Poiché la tua domanda era per il rilevamento quando non è supportata, ti consiglio di usarla in questo modo:

if (!isCanvasSupported()){ ...

14
Perché la doppia negazione (!!) sta per?

16
Se Canvas non c'è elem.getContext == undefined,. !undefined = truee !true = false, quindi, questo ci consente di restituire un bool, piuttosto che indefinito o il contesto.
Rich Bradshaw,

1
@ 2astalavista Il doppio negativo (!!) è come il casting. Trasforma un'affermazione truey o falsey in un valore booleano. Ad esempio: var i = 0. viene valutato come falso, ma il tipo di i restituisce "numero". typeof !! I restituisce "booleano".
Utente2

Un altro modo per "lanciare" in booleano è: undefined ? true : false(anche se un po 'più lungo).
vcapra1

1
Dovrei notare che ci sono diversi tipi di supporto canvas. Le prime implementazioni del browser non supportavano toDataURL. E Opera Mini supporta solo il rendering canvas di base senza supporto API di testo . Opera Mini può essere esclusa in questo modo , solo per riferimento incrociato.
hexalys,

103

Esistono due metodi popolari per rilevare il supporto canvas nei browser:

  1. Il suggerimento di Matt di verificare l'esistenza di getContext, usato anche in modo simile dalla biblioteca di Modernizr:

    var canvasSupported = !!document.createElement("canvas").getContext;
  2. Verifica dell'esistenza HTMLCanvasElementdell'interfaccia, come definito dalle specifiche WebIDL e HTML . Questo approccio è stato raccomandato anche in un post sul blog del team di IE 9 .

    var canvasSupported = !!window.HTMLCanvasElement;

La mia raccomandazione è una variazione di quest'ultima (vedi Note aggiuntive ), per diversi motivi:

  • Ogni browser noto che supporta canvas - incluso IE 9 - implementa questa interfaccia;
  • È più conciso e immediatamente ovvio cosa sta facendo il codice;
  • L' getContextapproccio è significativamente più lento in tutti i browser , poiché prevede la creazione di un elemento HTML. Questo non è l'ideale quando è necessario spremere quante più prestazioni possibili (in una libreria come Modernizr, per esempio).

Non ci sono vantaggi evidenti nell'uso del primo metodo. Entrambi gli approcci possono essere falsificati, ma ciò non è probabile che accada per caso.

Note aggiuntive

Potrebbe essere ancora necessario verificare che sia possibile recuperare un contesto 2D. Secondo quanto riferito, alcuni browser mobili possono restituire true per entrambi i controlli precedenti, ma restituiscono nullper .getContext('2d'). Questo è il motivo per cui Modernizr controlla anche il risultato di .getContext('2d'). Tuttavia, WebIDL e HTML - ancora una volta - ci offrono un'altra opzione migliore e più veloce :

var canvas2DSupported = !!window.CanvasRenderingContext2D;

Si noti che possiamo saltare completamente il controllo dell'elemento canvas e passare direttamente al controllo del supporto per il rendering 2D. L' CanvasRenderingContext2Dinterfaccia fa anche parte delle specifiche HTML.

È necessario utilizzare l' getContextapproccio per rilevare il supporto WebGL perché, anche se il browser potrebbe supportare il WebGLRenderingContext, getContext()potrebbe restituire null se il browser non è in grado di interfacciarsi con la GPU a causa di problemi del driver e non è presente alcuna implementazione software. In questo caso, il controllo dell'interfaccia consente innanzitutto di saltare il controllo di 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
    }
}

Confronto delle prestazioni

Le prestazioni getContextdell'approccio sono più lente dell'85-90% in Firefox 11 e Opera 11 e circa il 55% più lente in Chromium 18.

    Tabella di confronto semplice, fare clic per eseguire un test nel browser


10
Nokia S60 e Blackberry Storm sono alcuni dei dispositivi che saranno falsi positivi sui rilevamenti di tele 2D proposti. Sfortunatamente, il cellulare diventa molto peloso e i fornitori non seguono le regole. :( Quindi finiamo con test più completi (cioè più lenti) per assicurare risultati accurati.
Paul Irish

@Paul: è interessante, ho testato gli emulatori BlackBerry Storm, tutti restituiti falsesia per il tuo esempio che per il mio, sembra che non forniscano l' CanvasRenderingContext2Dinterfaccia. Non sono ancora riuscito a testare l'S60, sono ancora molto curioso e potrei farlo presto, però.
Andy E

1
Questo è interessante, ma fino a quando il test arriva sotto un centinaio di millis, non va bene? Immagino che siano comunque tutti molto più veloci di così. Se memorizzi una funzione che lo verifica, devi solo pagare il costo una volta.
Ha disegnato Noakes il

1
Ho eseguito il tuo benchmark e anche l'approccio "lento" può essere fatto ~ 800.000 volte al secondo. Ancora una volta, se il risultato viene memorizzato nella cache, la decisione su quale approccio usare dovrebbe essere basata sulla robustezza, non sulle prestazioni (supponendo che ci sia una differenza nella robustezza).
Drew Noakes

@DrewNoakes: sì, dovresti quasi sempre cercare compatibilità sulla velocità. La mia tesi è che sto confutando le affermazioni sulla compatibilità di Paul, sulla base dei miei test in almeno uno dei browser problematici che ha menzionato nel suo commento. Non sono stato in grado di testare l'altro browser ma non sono convinto che ci sia un problema. Dovresti sempre mirare a ottenere le migliori prestazioni possibili, senza sacrificare la compatibilità. Non sto parlando di microottimizzazione, ma se stai eseguendo centinaia di test e non sono tutti ottimizzati, sì, può fare la differenza.
Andy E,

13

Di solito eseguo un controllo per getContextquando creo il mio oggetto canvas.

(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 è supportato, è possibile continuare l'installazione della tela e aggiungerla al DOM. Questo è un semplice esempio di Progressive Enhancement , che io (personalmente) preferisco al Graceful Degradation.


È un randagio , contextsulla seconda linea?
brainjam,

7
@brainjam - No, uso quella variabile vicino alla fine del codice. Provo a seguire le 'raccomandazioni' di JSLint (in questo caso .. solo 1 varistruzione per funzione).
Matt,

6

Perché non provare modernizr ? È una libreria JS che fornisce funzionalità di rilevamento.

Citazione:

Hai mai desiderato di fare dichiarazioni if ​​nel tuo CSS per la disponibilità di funzioni interessanti come border-radius? Bene, con Modernizr puoi realizzare proprio questo!


2
Il test che usiamo in modernizr è questo: return !!document.createElement('canvas').getContext questo è sicuramente il modo migliore per testare.
Paul Irish,

4
Modernizr è una libreria utile, ma sarebbe un po 'inutile estrarre l'intera libreria solo per rilevare il supporto della tela. Se è necessario rilevare anche altre funzionalità, lo consiglio.
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

Potrebbe esserci un gotcha qui: alcuni client non supportano tutti i metodi 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

Puoi usare lo script canisuse.js per rilevare se il tuo browser supporta canvas o meno

caniuse.canvas()

0

Se hai intenzione di ottenere il contesto della tua tela, potresti anche usarla come test:

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 :(*/
}
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.