Cách tốt nhất để phát hiện rằng HTML5 <canvas> không được hỗ trợ


139

Cách tiêu chuẩn để xử lý các tình huống trong đó trình duyệt không hỗ trợ <canvas>thẻ HTML5 là nhúng một số nội dung dự phòng như:

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

Nhưng phần còn lại của trang vẫn giữ nguyên, có thể không phù hợp hoặc gây hiểu nhầm. Tôi muốn một số cách phát hiện canvas không hỗ trợ để tôi có thể trình bày phần còn lại của trang của mình cho phù hợp. Bạn muốn giới thiệu gì?

Câu trả lời:


217

Đây là kỹ thuật được sử dụng trong Modernizr và về cơ bản mọi thư viện khác hoạt động canvas:

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

Vì câu hỏi của bạn là để phát hiện khi nó không được hỗ trợ, tôi khuyên bạn nên sử dụng nó như vậy:

if (!isCanvasSupported()){ ...

14
Tại sao phủ định kép (!!) là viết tắt của?

16
Nếu Canvas không có ở đó , elem.getContext == undefined. !undefined = true!true = false, do đó, điều này cho phép chúng ta trả về một bool, thay vì không xác định hoặc bối cảnh.
Giàu Bradshaw

1
@ 2astalavista Âm kép (!!) giống như đúc. Nó biến một tuyên bố đúng hoặc falsey thành một boolean. Ví dụ : var i = 0. tôi đánh giá là sai, nhưng typeof tôi trả về "số". typeof !! tôi trả về "boolean".
dùng2

Một cách khác để "cast" thành boolean là: undefined ? true : false(mặc dù dài hơn một chút).
vcapra1

1
Tôi nên lưu ý rằng có nhiều loại hỗ trợ vải khác nhau. Việc triển khai trình duyệt sớm không hỗ trợ toDataURL. Và Opera Mini chỉ hỗ trợ kết xuất canvas cơ bản mà không hỗ trợ API văn bản . Opera Mini có thể được loại trừ theo cách này , chỉ để tham khảo chéo.
hexalys

103

Có hai phương pháp phổ biến để phát hiện hỗ trợ canvas trong trình duyệt:

  1. Đề nghị của Matt về việc kiểm tra sự tồn tại củagetContext , cũng được thư viện Modernizr sử dụng theo cách tương tự:

    var canvasSupported = !!document.createElement("canvas").getContext;
  2. Kiểm tra sự tồn tại của HTMLCanvasElementgiao diện, như được xác định bởi thông số kỹ thuật WebIDLHTML . Cách tiếp cận này cũng được đề xuất trong một bài đăng trên blog của nhóm IE 9 .

    var canvasSupported = !!window.HTMLCanvasElement;

Đề xuất của tôi là một biến thể của cái sau (xem Ghi chú bổ sung ), vì một số lý do:

  • Mọi trình duyệt được biết đến hỗ trợ canvas - bao gồm IE 9 - thực hiện giao diện này;
  • Nó ngắn gọn hơn và rõ ràng ngay lập tức những gì mã đang làm;
  • Cách getContexttiếp cận chậm hơn đáng kể trên tất cả các trình duyệt , vì nó liên quan đến việc tạo một phần tử HTML. Điều này không lý tưởng khi bạn cần siết càng nhiều hiệu suất càng tốt (ví dụ trong một thư viện như Modernizr).

Không có lợi ích đáng chú ý khi sử dụng phương pháp đầu tiên. Cả hai cách tiếp cận đều có thể bị giả mạo, nhưng điều này không có khả năng xảy ra do tai nạn.

Ghi chú bổ sung

Có thể vẫn cần kiểm tra xem có thể lấy bối cảnh 2D không. Được biết, một số trình duyệt di động có thể trở thành sự thật cho cả trên séc, nhưng trở lại nullcho .getContext('2d'). Đây là lý do tại sao Modernizr cũng kiểm tra kết quả của .getContext('2d'). Tuy nhiên, WebIDL & HTML - một lần nữa - cung cấp cho chúng tôi một tùy chọn khác tốt hơn, nhanh hơn :

var canvas2DSupported = !!window.CanvasRenderingContext2D;

Lưu ý rằng chúng ta có thể bỏ qua việc kiểm tra hoàn toàn phần tử canvas và chuyển thẳng sang kiểm tra hỗ trợ kết xuất 2D. Các CanvasRenderingContext2Dgiao diện cũng là một phần của đặc tả HTML.

Bạn phải sử dụng getContextphương pháp để phát hiện hỗ trợ WebGL vì mặc dù trình duyệt có thể hỗ trợ WebGLRenderingContextnhưng getContext()có thể trả về null nếu trình duyệt không thể giao tiếp với GPU do sự cố trình điều khiển và không có phần mềm triển khai. Trong trường hợp này, việc kiểm tra giao diện trước tiên cho phép bạn bỏ qua việc kiểm tra 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
    }
}

So sánh hiệu suất

Hiệu suất của getContextphương pháp này chậm hơn 85-90% trong Firefox 11 và Opera 11 và chậm hơn khoảng 55% trong Chromium 18.

    Bảng so sánh đơn giản, nhấp để chạy thử nghiệm trong trình duyệt của bạn


10
Nokia S60 và Blackberry Storm là một trong số các thiết bị sẽ dương tính giả trên các phát hiện canvas 2D được đề xuất của bạn. Thật không may, điện thoại di động rất nhiều lông và các nhà cung cấp không tuân theo các quy tắc. :( Vì vậy, chúng tôi kết thúc với các bài kiểm tra đầy đủ hơn (tức là chậm hơn) để đảm bảo kết quả chính xác.
Paul Irish

@Paul: Thật thú vị, tôi đã thử nghiệm trình giả lập BlackBerry Storm, tất cả chúng đều trả về falsecho cả ví dụ của bạn và của tôi, có vẻ như chúng không cung cấp CanvasRenderingContext2Dgiao diện. Cho đến giờ tôi vẫn chưa thể kiểm tra S60, tôi vẫn rất tò mò và có thể sẽ sớm thực hiện điều đó.
Andy E

1
Điều này thật thú vị, nhưng miễn là bài kiểm tra đến dưới một trăm triệu, điều đó có ổn không? Tôi tưởng tượng rằng tất cả họ đều nhanh hơn thế nhiều. Nếu bạn ghi nhớ một chức năng kiểm tra điều này thì bạn chỉ cần trả chi phí một lần.
Drew Noakes

1
Tôi đã chạy điểm chuẩn của bạn và thậm chí phương pháp 'chậm' có thể được thực hiện ~ 800.000 lần một giây. Một lần nữa, nếu kết quả được lưu trong bộ nhớ cache thì quyết định sử dụng phương pháp nào sẽ dựa trên độ mạnh chứ không phải hiệu suất (giả sử có sự khác biệt về độ mạnh.)
Drew Noakes 16/1/13

@DrewNoakes: có, bạn hầu như luôn luôn đi để tương thích với tốc độ. Lập luận của tôi là tôi đang bác bỏ các yêu cầu tương thích của Paul, dựa trên thử nghiệm của riêng tôi trong ít nhất một trong những trình duyệt có vấn đề mà anh ấy đề cập trong bình luận của mình. Tôi đã không thể kiểm tra trình duyệt khác nhưng tôi vẫn không tin rằng có vấn đề. Bạn nên luôn luôn nhắm đến việc có được hiệu suất tốt nhất có thể, mà không phải hy sinh tính tương thích. Tôi không nói về tối ưu hóa vi mô, nhưng nếu bạn đang chạy hàng trăm thử nghiệm và tất cả chúng đều không được đánh giá cao thì, vâng, nó có thể tạo ra sự khác biệt.
Andy E

13

Tôi thường chạy một kiểm tra getContextkhi tôi tạo đối tượng canvas của tôi.

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

Nếu nó được hỗ trợ, thì bạn có thể tiếp tục thiết lập canvas và thêm nó vào DOM. Đây là một ví dụ đơn giản về Tăng cường tiến bộ , mà tôi (cá nhân) thích hơn Suy thoái duyên dáng.


Đó có phải là một đi lạc , contexttrên dòng thứ hai?
brainjam

7
@brainjam - Không, tôi sử dụng biến đó ở gần cuối mã. Tôi cố gắng làm theo 'khuyến nghị' của JSLint (trong trường hợp này .. chỉ có 1 varcâu lệnh cho mỗi hàm).
Matt

6

Tại sao không thử Modernizr ? Đó là một thư viện JS cung cấp khả năng phát hiện.

Trích dẫn:

Bạn đã bao giờ muốn thực hiện if-statement trong CSS của mình để có sẵn các tính năng thú vị như bán kính đường viền chưa? Chà, với Modernizr bạn có thể hoàn thành điều đó!


2
Bài kiểm tra mà chúng tôi sử dụng trong Modernizr là thế này: return !!document.createElement('canvas').getContext Đó chắc chắn là cách tốt nhất để kiểm tra.
Paul Ailen

4
Modernizr là một thư viện hữu ích, nhưng sẽ hơi lãng phí khi kéo toàn bộ thư viện chỉ để phát hiện hỗ trợ canvas. Nếu bạn cũng cần phát hiện các tính năng khác thì tôi khuyên bạn nên sử dụng nó.
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

Có thể có một gotcha ở đây - một số khách hàng không hỗ trợ tất cả các phương thức 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

Bạn có thể sử dụng tập lệnh canisuse.js để phát hiện xem trình duyệt của bạn có hỗ trợ canvas hay không

caniuse.canvas()

0

Nếu bạn định lấy bối cảnh của khung vẽ, bạn cũng có thể sử dụng nó làm thử nghiệm:

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 :(*/
}
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.