La mejor manera de detectar que HTML5 <canvas> no es compatible

139

La forma estándar de lidiar con situaciones en las que el navegador no admite la <canvas>etiqueta HTML5 es incrustar contenido alternativo como:

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

Pero el resto de la página sigue siendo la misma, lo que puede ser inapropiado o engañoso. Quisiera alguna forma de detectar la falta de soporte del lienzo para poder presentar el resto de mi página en consecuencia. ¿Qué recomendarías?

brainjam
fuente

Respuestas:

217

Esta es la técnica utilizada en Modernizr y, básicamente, en todas las demás bibliotecas que realizan trabajos de lienzo:

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

Debido a que su pregunta era para la detección cuando está no apoyado, recomiendo usarlo de esta manera:

if (!isCanvasSupported()){ ...
Paul irlandés
fuente
14
¿Por qué significa la doble negación (!!)?
16
Si Canvas no está allí elem.getContext == undefined,. !undefined = true, y !true = false, así que esto nos permite devolver un bool, en lugar de indefinido o el contexto.
Rich Bradshaw
1
@ 2astalavista El doble negativo (!!) es como un casting. Convierte una declaración verdadera o falsa en un booleano. Por ejemplo: var i = 0. evalúo como falso, pero typeof i devuelve "número". typeof !! i devuelve "boolean".
Usuario2
Otra forma de "convertir" a booleano es: undefined ? true : false(aunque un poco más largo).
vcapra1
1
Debo señalar que hay diferentes tipos de soporte de lienzo. Las primeras implementaciones del navegador no eran compatibles toDataURL. Y Opera Mini solo admite la representación básica del lienzo sin compatibilidad con API de texto . Opera Mini se puede excluir de esta manera , solo por referencia cruzada.
hexalys
103

Existen dos métodos populares para detectar el soporte de lienzo en los navegadores:

  1. La sugerencia de Matt de verificar la existencia de getContext, también utilizada de manera similar por la biblioteca Modernizr:

    var canvasSupported = !!document.createElement("canvas").getContext;
  2. Comprobación de la existencia de la HTMLCanvasElementinterfaz, tal como se define en las especificaciones WebIDL y HTML . Este enfoque también fue recomendado en una publicación de blog del equipo de IE 9 .

    var canvasSupported = !!window.HTMLCanvasElement;

Mi recomendación es una variación de este último (ver Notas adicionales ), por varias razones:

  • Todos los navegadores conocidos que soportan el lienzo, incluido IE 9, implementan esta interfaz;
  • Es más conciso e instantáneamente obvio lo que está haciendo el código;
  • El getContextenfoque es significativamente más lento en todos los navegadores , ya que implica la creación de un elemento HTML. Esto no es ideal cuando necesita exprimir tanto rendimiento como sea posible (en una biblioteca como Modernizr, por ejemplo).

No hay beneficios notables al usar el primer método. Ambos enfoques pueden ser falsificados, pero no es probable que esto suceda por accidente.

Notas adicionales

Todavía puede ser necesario verificar que se pueda recuperar un contexto 2D. Según se informa, algunos navegadores móviles pueden ser válidos para las dos comprobaciones anteriores, pero también nullpara .getContext('2d'). Es por eso que Modernizr también verifica el resultado de .getContext('2d'). Sin embargo, WebIDL y HTML, nuevamente, nos brindan otra opción mejor y más rápida :

var canvas2DSupported = !!window.CanvasRenderingContext2D;

Tenga en cuenta que podemos omitir la comprobación del elemento del lienzo por completo y pasar directamente a la comprobación de la compatibilidad con la representación 2D. La CanvasRenderingContext2Dinterfaz también es parte de la especificación HTML.

Usted debe usar el getContextmétodo para la detección de WebGL apoyo porque, a pesar de que el navegador puede apoyar el WebGLRenderingContext, getContext()puede devolver nulo si el navegador no es capaz de interactuar con la GPU debido a problemas con los controladores y no hay ninguna aplicación de software. En este caso, la comprobación de la interfaz primero le permite omitir la comprobación 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
    }
}

Comparación de rendimiento

El rendimiento del getContextenfoque es 85-90% más lento en Firefox 11 y Opera 11 y aproximadamente 55% más lento en Chromium 18.

    Tabla de comparación simple, haga clic para ejecutar una prueba en su navegador

Andy E
fuente
10
Nokia S60 y Blackberry Storm se encuentran entre algunos de los dispositivos que detectarán falsos positivos en su propuesta de lienzo 2D Desafortunadamente, los dispositivos móviles son muy complicados y los vendedores no siguen las reglas. :( Así que terminamos con pruebas más completas (es decir, más lentas) para asegurar resultados precisos.
Paul Irish
@Paul: eso es interesante, probé los emuladores de BlackBerry Storm, todos volvieron falsetanto para tu ejemplo como para el mío, parece que no proporcionan la CanvasRenderingContext2Dinterfaz. Hasta ahora no he podido probar el S60, todavía tengo mucha curiosidad y puedo hacerlo pronto.
Andy E
1
Esto es interesante, pero mientras la prueba llegue a menos de cien milis, ¿no está bien? Me imagino que todos son mucho más rápidos que eso de todos modos. Si memoriza una función que prueba esto, solo debe pagar el costo una vez.
Drew Noakes
1
Ejecuté su punto de referencia e incluso el enfoque 'lento' se puede hacer ~ 800,000 veces por segundo. Una vez más, si el resultado se almacena en caché entonces la decisión sobre qué método utilizar debe basarse en robustez, no el rendimiento (suponiendo que hay una diferencia en solidez.)
a Drew Noakes
@DrewNoakes: sí, casi siempre debes buscar compatibilidad con la velocidad. Mi argumento es que estoy refutando las afirmaciones de compatibilidad de Paul, basadas en mis propias pruebas en al menos uno de los buscadores de problemas que mencionó en su comentario. No he podido probar el otro navegador, pero no estoy convencido de que haya un problema. Siempre debe apuntar a obtener el mejor rendimiento posible, sin sacrificar la compatibilidad. No estoy hablando de micro-optimización, pero si está ejecutando cientos de pruebas y todas no están optimizadas, sí, puede marcar la diferencia.
Andy E
13

Normalmente ejecuto una comprobación para getContextcuando creo mi objeto de lienzo.

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

Si es compatible, puede continuar con la configuración del lienzo y agregarlo al DOM. Este es un ejemplo simple de mejora progresiva , que yo (personalmente) prefiero a la degradación agraciada.

Mate
fuente
¿Es eso un callejero , contexten la segunda línea?
brainjam
77
@brainjam - No, uso esa variable cerca del final del código. Intento seguir las 'recomendaciones' de JSLint (en este caso ... solo 1 vardeclaración por función).
Matt
6

¿Por qué no probar modernizr ? Es una biblioteca JS que proporciona capacidad de detección.

Citar:

¿Alguna vez ha querido hacer declaraciones if en su CSS para la disponibilidad de características interesantes como border-radius? Bueno, con Modernizr puedes lograr eso.

Frozenskys
fuente
2
La prueba que usamos en modernizr es la siguiente: return !!document.createElement('canvas').getContext esa es definitivamente la mejor manera de probar.
Paul Irish
44
Modernizr es una biblioteca útil, pero sería un desperdicio extraer toda la biblioteca solo para detectar el soporte del lienzo. Si necesita detectar otras funciones también, lo recomendaría.
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.");
}
Sheikh Ali
fuente
1

Puede haber un problema aquí: algunos clientes no admiten todos los métodos de lienzo.

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
fuente
0

Puede usar el script canisuse.js para detectar si sus navegadores son compatibles con el lienzo o no

caniuse.canvas()
Beka
fuente
0

Si va a obtener el contexto de su lienzo, podría usarlo como prueba:

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
fuente