Лучший способ определить, что HTML5 <canvas> не поддерживается

139

Стандартный способ справиться с ситуациями, когда браузер не поддерживает <canvas>тег HTML5, - это встроить резервный контент, например:

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

Но остальная часть страницы остается прежней, что может быть неуместным или вводящим в заблуждение. Я хотел бы каким-то образом обнаружить отсутствие поддержки холста, чтобы я мог соответствующим образом представить остальную часть моей страницы. Чтобы вы посоветовали?

мозговая пробка
источник

Ответы:

217

Это метод, используемый в Modernizr и практически во всех других библиотеках, которые работают с холстами:

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

Поскольку ваш вопрос касался обнаружения, когда он не поддерживается, я рекомендую использовать его так:

if (!isCanvasSupported()){ ...
Пол Айриш
источник
15
Почему стоит двойное отрицание (!!)?
16
Если Canvas нет, elem.getContext == undefined. !undefined = true, и !true = false, таким образом, это позволяет нам возвращать логическое значение, а не undefined или контекст.
Rich Bradshaw
1
@ 2astalavista Двойной минус (!!) похож на кастинг. Он превращает истинное или ложное утверждение в логическое значение. Например: var i = 0. i оценивается как ложь, но typeof i возвращает «число». typeof !! i возвращает "логическое".
User2
Другой способ «преобразовать» в логическое значение: undefined ? true : false(хотя и немного длиннее).
vcapra1 01
1
Следует отметить, что существуют разные типы опор холста. Ранние версии браузеров не поддерживали toDataURL. А Opera Mini поддерживает только базовую визуализацию холста без поддержки текстового API . Opera Mini может быть исключена таким образом только для перекрестной ссылки.
hexalys
103

Есть два популярных метода определения поддержки холста в браузерах:

  1. Предложение Мэтта о проверке существования getContext, также используется аналогичным образом библиотекой Modernizr:

    var canvasSupported = !!document.createElement("canvas").getContext;
    
  2. Проверка наличия HTMLCanvasElementинтерфейса в соответствии со спецификациями WebIDL и HTML . Этот подход также был рекомендован в сообщении в блоге команды IE 9 .

    var canvasSupported = !!window.HTMLCanvasElement;
    

Я рекомендую вариант последнего (см. Дополнительные примечания ) по нескольким причинам:

  • Каждый известный браузер, поддерживающий холст, включая IE 9, реализует этот интерфейс;
  • Это более лаконично и сразу становится очевидным, что делает код;
  • Этот getContextподход значительно медленнее во всех браузерах , поскольку предполагает создание элемента HTML. Это не идеально, когда вам нужно максимально увеличить производительность (например, в такой библиотеке, как Modernizr).

Использование первого метода не дает заметных преимуществ. Оба подхода можно подделать, но это вряд ли произойдет случайно.

Дополнительные примечания

По-прежнему может потребоваться проверка возможности получения 2D-контекста. Как сообщается, некоторые мобильные браузеры могут возвращать истину для обеих вышеуказанных проверок, но возвращают nullдля .getContext('2d'). Вот почему Modernizr также проверяет результат .getContext('2d'). Однако WebIDL и HTML - опять же - дают нам еще один лучший и более быстрый вариант:

var canvas2DSupported = !!window.CanvasRenderingContext2D;

Обратите внимание, что мы можем полностью пропустить проверку элемента холста и сразу перейти к проверке поддержки 2D-рендеринга. CanvasRenderingContext2DИнтерфейс также является частью HTML спецификации.

Вы должны использовать getContextподход для обнаружения поддержки WebGL, потому что, даже если браузер может поддерживать WebGLRenderingContext, getContext()может возвращать значение 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подхода на 85-90% ниже в Firefox 11 и Opera 11 и примерно на 55% ниже в Chromium 18.

    Простая сравнительная таблица, нажмите, чтобы запустить тест в своем браузере

Энди Э
источник
10
Nokia S60 и Blackberry Storm являются одними из устройств, которые обнаруживают ложные срабатывания при обнаружении предлагаемого вами 2D-холста. К сожалению, мобильные устройства становятся очень опасными, а поставщики не соблюдают правила. :( Таким образом, мы получаем более полные (то есть более медленные) тесты, чтобы гарантировать точные результаты.
Пол Айриш
@Paul: это интересно, я тестировал эмуляторы BlackBerry Storm, все они вернулись falseкак для вашего примера, так и для моего, похоже, они не предоставляют CanvasRenderingContext2Dинтерфейс. Я пока не смог протестировать S60, мне все еще очень любопытно, и, возможно, скоро это сделаю.
Энди Э
1
Это интересно, но пока результат теста составляет менее ста миллисекунд, разве это не нормально? Я полагаю, что все они в любом случае намного быстрее. Если вы запомнили функцию, которая проверяет это, вам нужно оплатить стоимость только один раз.
Дрю Ноукс
1
Я провел ваш тест, и даже «медленный» подход можно выполнять ~ 800 000 раз в секунду. Опять же, если результат кэшируется, тогда решение о том, какой подход использовать, должно основываться на надежности, а не на производительности (при условии, что есть разница в надежности).
Дрю Ноукс
@DrewNoakes: да, вы почти всегда должны стремиться к совместимости, а не к скорости. Мой аргумент состоит в том, что я опровергаю утверждения Пола о совместимости, основанные на моем собственном тестировании по крайней мере в одном из проблемных браузеров, которые он упомянул в своем комментарии. Мне не удалось протестировать другой браузер, но я по-прежнему не уверен, что это проблема. Вы всегда должны стремиться к максимальной производительности, не жертвуя совместимостью. Я не говорю о микрооптимизации, но если вы проводите сотни тестов, и все они неоптимизированы, то да, это может иметь значение.
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
7
@brainjam - Нет, я использую эту переменную в конце кода. Я стараюсь следовать «рекомендациям» JSLint (в данном случае только 1 varоператор на функцию).
Мэтт
6

Почему бы не попробовать модернизр ? Это библиотека JS, обеспечивающая возможность обнаружения.

Цитата:

Вы когда-нибудь хотели сделать if-выражения в своем CSS для доступности таких интересных функций, как border-radius? Что ж, с Modernizr вы можете этого добиться!

Frozenskys
источник
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

Здесь может быть ошибка - некоторые клиенты поддерживают не все методы холста.

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
источник
0

Вы можете использовать скрипт canisuse.js, чтобы определить, поддерживает ли ваш браузер холст или нет.

caniuse.canvas()
Бека
источник
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 :(*/
}
Каллум Хайнс
источник