JavaScriptによってインタラクティブなコンテンツを実現する際の問題点として、アクセシビリティの低下があります。特にCanvas APIの描画内容はDOMドキュメントの構造には反映されないので、Webブラウザ組み込みのキーボード操作や読み上げといった機能がまったく適用されません。
Canvas APIの解説の締めとして、そうしたアクセシビリティの欠如を改善するための工夫を取り上げます。
記事の冒頭でも触れましたが、canvasタグの内部に記述した内容はcanvas未対応のブラウザでのみ表示されます。そこに適切な代替コンテンツを含めることで、音声ブラウザなどのユーザーにも表示内容を伝えることができます。特にインタラクティブな動作をしない場合は、これだけで十分な場合も多いでしょう。
代替コンテンツの内容としては、Canvas APIによる表示内容を具体的に説明する文章が強く推奨されています。「xxxとyyyの商品画像を交互に表示」というような、それだけでユーザーが表示内容を把握できるものにするのがよいでしょう。
代替コンテンツ(canvasタグ内の内容)はCanvas APIに対応したブラウザでは表示されないと書きましたが、これにはもう少し補足事項があります。HTML5の規格では、代替コンテンツにリンクやボタンなどの操作可能な要素が含まれる場合、表示こそされませんがTABキーによるフォーカス移動やEnterキーによる選択などは通常どおり機能することになっています(「規格では」と断りを入れた理由は後述)。
従って、代替コンテンツにCanvas APIで描画するのと同等のUIを含めておけば、音声ブラウザのユーザーやマウスが使えないユーザーでも操作が可能になります。ただし、フォーカスリング等は自動では表示されないため、focusやblurのイベントで表示を更新し、自前でボタンの強調表示などを行う必要があります。
これらを踏まえて、Canvas APIでキーボード操作も可能なボタンを実装した例を以下に示します。タブキーでbuttonタグをフォーカスすると画面上の矩形に枠が表示され、Enterキーでalertが表示されます。
<!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title>Canvas APIのアクセシビリティ</title> </head> <body> <canvas id="canvas" width="400" height="200"> <button onfocus="redraw(true);" onblur="redraw(false);" onclick="clicked();">ボタン</button> </canvas> <script> var canvas = document.getElementById('canvas'); var ctx = null; // 描画コンテキストを取得する if(canvas && typeof(canvas.getContext) === 'function') { ctx = canvas.getContext('2d'); } if(ctx) { // ボタンの領域を示すパスを構築 function buildPath() { ctx.beginPath(); ctx.rect(10, 10, 380, 180); } // ボタンの描画 function redraw(focus) { ctx.clearRect(0, 0, 400, 200); buildPath(); ctx.fillStyle = "#fcc"; ctx.fill(); if(focus) { ctx.lineWidth = 4; ctx.strokeStyle = "#f00"; ctx.stroke(); } ctx.fillStyle = "black" ctx.font = "normal bold 40px sans-serif"; ctx.textAlign = "center"; ctx.textBaseline = "middle"; ctx.fillText('ここをクリック', 200, 100); } redraw(false); // canvasタグのクリック処理 canvas.onclick = function(e) { var x = e.clientX + window.pageXOffset - canvas.offsetLeft; var y = e.clientY + window.pageYOffset - canvas.offsetTop; buildPath(); if(ctx.isPointInPath(x, y)) { clicked(); } }; // ボタンが押された時の処理 function clicked() { alert('ボタンが押されました'); } } </script> </body> </html>
このように、HTML5の規格ではCanvas APIによる表示でもアクセシビリティが確保できる配慮がなされています。しかし、残念ながらこの挙動をサポートしているWebブラウザは限られており、執筆時点ではIE9とFirefox 14のみです(Google Chromeはバージョン22でサポートするようです)。他のブラウザは代替コンテンツの内容を単純に無視してしまい、ボタンなどがフォーカスを受けることはありません。上記の例も、(執筆時点において)IE9とFirefox 14以外では動作しません。
とはいえ、すべてのブラウザがサポートしていなくても、アクセシビリティに配慮する意味がないわけではありません。「対応ブラウザを使えば操作できる」と「どのブラウザでも操作できない」では天と地ほどの差があります。それに、この機能を活用したWebページが増えることで、現在未対応のブラウザベンダにモチベーションを与えることにもなるでしょう。コンテンツによっては難しい場合もあるでしょうが、Canvas APIを採用する際には、ぜひアクセシビリティについても検討してください。
最後に、前回までに解説したSVGと今回のCanvas APIの使い分けについて触れておきます。SVGとCanvas APIはいずれもWebブラウザ上で使える2次元グラフィックAPIであり、両者のユースケースは重なる部分が多くあります。そうなると、シンプルで学習が容易なCanvas APIをつい使ってしまいたくなるかもしれません。
しかし、SVGとCanvas APIのどちらでも目的が達成できる場合、筆者はSVGの採用をお勧めします。なぜなら、SVGは表示内容をDOMで表現するため、ブラウザがそれを理解できます。SVG中のテキストは容易に抽出できますし、リンクに対するフォーカス制御もブラウザが処理してくれます。特別な工夫なく使った場合、SVGの方がユーザーにとって使いやすいものになる可能性が高いのです。
その上で、目的がCanvas APIでないと実現できない、もしくはより効率良く実現できる場合のみ、Canvas APIを採用するとよいでしょう。例えば以下のような処理です。
さらいえば、SVGとCanvas APIは必ずしもを排他的な存在ではありません。toDataURL()やforeignObjectを使えば、Canvas APIの描画結果をSVGに含めることができます。また、Canvas APIを使ってSVGを表示するCanVGのようなライブラリもあります。これらを利用すれば、両者のメリットをうまく組み合わせることも可能でしょう。
いずれにしても、まずは両者の機能を正しく把握することが重要です。その上で、目的に合わせて適材適所で使い分けるようにしてください。
伊藤 千光
白髪になってもプログラムを組んでいたい、ゲームプログラマあがりのWebエンジニア。日本ファルコム、Microsoft GameStudios JapanにてPCやXbox、Xbox 360のゲームの開発に従事し、グラフィックエンジンやコリジョン、スクリプトなどを幅広く担当。その後、全世界のコンピュータを1つにつなげるWeb技術に魅力を感じ、Webエンジニアに転身。Irvine SystemsにてRuby on Railsによるシステム開発に携わった後、フリーランスに。現在はGoogle AppsやGoogle App Engineなどを利用した案件をこなしつつ、ブログ「WebOS Goodies」にて情報発信を行っている。Google API Expert(ソーシャル担当)。WebOS Goodies : http://webos-goodies.jp/
Copyright © ITmedia, Inc. All Rights Reserved.