Найкращий спосіб виявити, що HTML5 <canvas> не підтримується


139

Стандартний спосіб вирішення ситуацій, коли веб-переглядач не підтримує <canvas>тег HTML5, - вставляти якийсь резервний вміст, наприклад:

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

Але решта сторінки залишається тією ж, що може бути невідповідним або оманливим. Мені б хотілося виявити непідтримку полотна, щоб я міг відповідно представити решту моєї сторінки. Що б ти порадив?

Відповіді:


217

Це техніка, яка використовується в "Модернізрі" і в основному у будь-якій іншій бібліотеці, яка працює на полотні:

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

Оскільки ваше питання стосувалося виявлення, коли воно не підтримується, рекомендую його використовувати так:

if (!isCanvasSupported()){ ...

14
Чому стоїть подвійне заперечення (!!)?

16
Якщо Canvas немає, elem.getContext == undefined. !undefined = true, і !true = false, таким чином, це дозволяє нам повернути крапку, а не визначити чи контекст.
Річ Бредшоу

1
@ 2astalavista Подвійний негатив (!!) - це як кастинг. Це перетворює правдиву заяву або фальси в булеву. Наприклад: var i = 0. Я оцінює значення false, але typeof я повертає "число". я повертаю "булева".
Користувач2

Ще один спосіб "кинути" на булевий: undefined ? true : false(хоч трохи довший).
vcapra1

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()може повернути нуль, якщо браузер не в змозі взаємодіяти з графічним процесором через проблеми з драйверами і не існує реалізації програмного забезпечення. У цьому випадку спочатку перевірка інтерфейсу дозволяє пропустити перевірку на 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: так, майже завжди слід прагнути до сумісності через швидкість. Мій аргумент полягає в тому, що я спростовую претензії на сумісність Павла, грунтуючись на моєму власному тестуванні хоча б в одному з проблемних браузерів, про які він згадував у своєму коментарі. Мені не вдалося протестувати інший браузер, але я не переконаний у тому, що є проблема. Ви завжди повинні прагнути досягти найкращої продуктивності, не приносячи шкоди сумісності. Я не говорю про мікрооптимізацію, але якщо ви проводите сотні тестів, і всі вони тоді неоптимізовані, так, це може змінити значення.
Енді Е

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, яка забезпечує можливість виявлення.

Цитата:

Ви коли-небудь хотіли робити у вашому CSS if-заяви для наявності класних функцій, таких як радіус межі? Що ж, за допомогою Modernizr ви можете досягти саме цього!


2
Тест, який ми використовуємо в модернізаторі, такий: 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)

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 :(*/
}
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.