Meilleur moyen de détecter que HTML5 <canvas> n'est pas pris en charge

139

La manière standard de gérer les situations où le navigateur ne prend pas en charge la <canvas>balise HTML5 consiste à intégrer du contenu de secours comme:

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

Mais le reste de la page reste le même, ce qui peut être inapproprié ou trompeur. Je voudrais un moyen de détecter le non-support du canevas afin de pouvoir présenter le reste de ma page en conséquence. Que recommanderais-tu?

cerveau
la source

Réponses:

217

C'est la technique utilisée dans Modernizr et fondamentalement toutes les autres bibliothèques qui font du travail de canevas:

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

Étant donné que votre question concernait la détection lorsqu'elle n'est pas prise en charge, je recommande de l'utiliser comme ceci:

if (!isCanvasSupported()){ ...
Paul Irish
la source
14
Pourquoi la double négation (!!) signifie-t-elle?
16
Si Canvas est pas là, elem.getContext == undefined. !undefined = true, et !true = false, donc cela nous permet de renvoyer un booléen, plutôt que non défini ou le contexte.
Rich Bradshaw
1
@ 2astalavista Le double négatif (!!) est comme un casting. Il transforme une déclaration truey ou falsey en un booléen. Par exemple: var i = 0. i donne la valeur false, mais typeof i renvoie «nombre». typeof !! i renvoie "booléen".
User2
Une autre façon de "convertir" en booléen est: undefined ? true : false(bien qu'un peu plus long).
vcapra1
1
Il convient de noter qu'il existe différents types de support de toile. Les premières implémentations de navigateur n'étaient pas prises en charge toDataURL. Et Opera Mini ne prend en charge que le rendu de canevas de base sans prise en charge d'API de texte . Opera Mini peut être exclu de cette façon , juste pour référence croisée.
hexalys
103

Il existe deux méthodes populaires pour détecter la prise en charge du canevas dans les navigateurs:

  1. Suggestion de Matt de vérifier l'existence de getContext, également utilisée de manière similaire par la bibliothèque Modernizr:

    var canvasSupported = !!document.createElement("canvas").getContext;
  2. Vérification de l'existence de l' HTMLCanvasElementinterface, telle que définie par les spécifications WebIDL et HTML . Cette approche a également été recommandée dans un article de blog de l'équipe IE 9 .

    var canvasSupported = !!window.HTMLCanvasElement;

Ma recommandation est une variante de ce dernier (voir Notes complémentaires ), pour plusieurs raisons:

  • Chaque navigateur connu prenant en charge le canevas - y compris IE 9 - implémente cette interface;
  • C'est plus concis et instantanément ce que fait le code;
  • L' getContextapproche est nettement plus lente sur tous les navigateurs , car elle implique la création d'un élément HTML. Ce n'est pas idéal lorsque vous avez besoin de réduire au maximum les performances (dans une bibliothèque comme Modernizr, par exemple).

Il n'y a aucun avantage notable à utiliser la première méthode. Les deux approches peuvent être falsifiées, mais cela ne se produira probablement pas par accident.

Notes complémentaires

Il peut encore être nécessaire de vérifier qu'un contexte 2D peut être récupéré. Selon certaines informations, certains navigateurs mobiles peuvent renvoyer true pour les deux vérifications ci-dessus, mais revenir nullpour .getContext('2d'). C'est pourquoi Modernizr vérifie également le résultat de .getContext('2d'). Cependant, WebIDL & HTML - encore une fois - nous offre une autre option meilleure et plus rapide :

var canvas2DSupported = !!window.CanvasRenderingContext2D;

Notez que nous pouvons ignorer entièrement la vérification de l'élément canvas et passer directement à la vérification de la prise en charge du rendu 2D. L' CanvasRenderingContext2Dinterface fait également partie de la spécification HTML.

Vous devez utiliser l' getContextapproche pour détecter la prise en charge de WebGL car, même si le navigateur prend en charge le WebGLRenderingContext, getContext()peut renvoyer null si le navigateur ne parvient pas à s'interfacer avec le GPU en raison de problèmes de pilote et qu'il n'y a pas d'implémentation logicielle. Dans ce cas, la vérification de l'interface en premier vous permet d'ignorer la vérification 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
    }
}

Comparaison des performances

Performance du getContext approche sont 85 à 90% plus lentes dans Firefox 11 et Opera 11 et environ 55% plus lentes dans Chromium 18.

    Tableau de comparaison simple, cliquez pour exécuter un test dans votre navigateur

Andy E
la source
10
Nokia S60 et le Blackberry Storm font partie des appareils qui seront détectés par des faux positifs sur votre canevas 2D proposé. Malheureusement, le mobile devient très poilu et les vendeurs ne suivent pas les règles. :( Nous nous retrouvons donc avec des tests plus complets (c'est-à-dire plus lents) pour garantir des résultats précis.
Paul Irish
@Paul: c'est intéressant, j'ai testé les émulateurs BlackBerry Storm, tous sont retournés falsepour votre exemple et le mien, il semble qu'ils ne fournissent pas l' CanvasRenderingContext2Dinterface. Je n'ai pas encore pu tester le S60, je suis toujours très curieux et je le ferai peut-être bientôt.
Andy E
1
C'est intéressant, mais tant que le test est inférieur à une centaine de millis, n'est-ce pas bien? J'imagine qu'ils sont tous beaucoup plus rapides que ça de toute façon. Si vous mémorisez une fonction qui teste cela, vous ne devez payer le coût qu'une seule fois.
Drew Noakes le
1
J'ai utilisé votre benchmark et même l'approche «lente» peut être appliquée ~ 800 000 fois par seconde. Encore une fois, si le résultat est mis en cache, la décision sur l'approche à utiliser doit être basée sur la robustesse, pas sur les performances (en supposant qu'il y ait une différence de robustesse.)
Drew Noakes
@DrewNoakes: oui, vous devriez presque toujours privilégier la compatibilité plutôt que la vitesse. Mon argument est que je réfute les affirmations de compatibilité de Paul, sur la base de mes propres tests dans au moins l'un des navigateurs problématiques qu'il a mentionnés dans son commentaire. Je n'ai pas pu tester l'autre navigateur, mais je ne suis toujours pas convaincu qu'il y ait un problème. Vous devez toujours viser à obtenir les meilleures performances possibles, sans sacrifier la compatibilité. Je ne parle pas de micro-optimisation, mais si vous exécutez des centaines de tests et qu'ils ne sont tous pas optimisés, oui, cela peut faire la différence.
Andy E
13

J'exécute généralement une vérification getContextlorsque je crée mon objet canevas.

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

S'il est pris en charge, vous pouvez continuer la configuration du canevas et l'ajouter au DOM. Ceci est un exemple simple d' amélioration progressive , que je préfère (personnellement) à la dégradation gracieuse.

Mat
la source
Est-ce une erreur , contextsur la deuxième ligne?
brainjam
7
@brainjam - Non, j'utilise cette variable vers la fin du code. J'essaye de suivre les «recommandations» de JSLint (dans ce cas .. seulement 1 varinstruction par fonction).
Matt
6

Pourquoi ne pas essayer modernizr ? C'est une bibliothèque JS qui offre une capacité de détection.

Citation:

Avez-vous déjà voulu faire des déclarations if dans votre CSS pour la disponibilité de fonctionnalités intéressantes telles que border-radius? Eh bien, avec Modernizr, vous pouvez accomplir exactement cela!

Frozenskys
la source
2
Le test que nous utilisons dans modernizr est le suivant: return !!document.createElement('canvas').getContext c'est certainement la meilleure façon de tester.
Paul Irish
4
Modernizr est une bibliothèque utile, mais ce serait un peu un gaspillage de récupérer toute la bibliothèque juste pour détecter la prise en charge de canvas. Si vous avez également besoin de détecter d'autres fonctionnalités, je le recommande.
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.");
}
Cheikh Ali
la source
1

Il peut y avoir un piège ici - certains clients ne prennent pas en charge toutes les méthodes de canevas.

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)
Kennebec
la source
0

Vous pouvez utiliser le script canisuse.js pour détecter si votre navigateur prend en charge canvas ou non

caniuse.canvas()
Beka
la source
0

Si vous voulez obtenir le contexte de votre canevas, vous pouvez aussi bien l'utiliser comme 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 :(*/
}
Callum Hynes
la source