Blog
Webにおける3Dコンテンツ内のアクセシビリティ対応について考える
canvas要素についてのおさらい
canvas要素とは、JavaScriptと組み合わせて、2Dや3Dのビジュアルを描くためのタグの一種です。<canvas>自体は単なる空の領域で、JSでグラフィックを表現します。
ちょっとリッチでインタラクティブなビジュアルやアニメーションを実装する際によく使われます。
また、MDN Web Docsでは、下記のように説明されています。
HTMLの <canvas> 要素 と キャンバススクリプティング API や WebGL API を使用して、グラフィックやアニメーションを描画することができます。
参考:canvas要素にthree.jsを使って立方体を描画するサンプル
canvas要素のアクセシビリティ
canvas要素について少し理解を深めたところで、アクセシビリティの実現について考えていきます。MDN Web Docsのcanvasについてのページを読み進めていくと、下記のような記述が見られます。
<canvas> 要素は単なるビットマップであり、描かれたオブジェクトに関する情報は提供しません。(中略)一般的に、アクセシビリティに配慮したウェブサイトやアプリではキャンバスを使用しないでください。
強く言い切られてしまいましたが、それでも表現の一環としてcanvas要素を使いたいタイミングは発生すると思います。
そこで、
- canvas要素が抱えるアクセシビリティの課題
- canvas要素でアクセシビリティを実現するための解決策
について、考えていきたいと思います。
canvas要素が抱えるアクセシビリティの課題
canvas要素とその他のタグ(<h>,<p>,<img>など)の違い・そこで発生する問題点について下記にまとめます。
代替テキストの不足
- <canvas>で描画される内容は動的で複雑な場合が多いため、その内容を簡潔にかつ正確にテキストで表現することが困難
- 画像の場合、
alt
属性を使って代替テキストを提供できるが、<canvas>にはalt属性がない- “代替コンテンツ”の設定は可能だが、canvas要素に対応しない古いブラウザーおよびJavaScriptが無効であるブラウザーで描画されるのに使われる
セマンティクスの欠如
- HTMLでは標準的なタグ(例:
<h1>
,<p>
,<ul>
,<button>
)を用いて要素にセマンティックな意味をもたせることができるが、canvas要素で描画された内容はセマンティクスな意味を持つことが出来ない
スクリーンリーダーとの互換性がない
- canvas要素内の個々の要素にARIA属性をつけることができない
- canvas要素で描画される内容は、通常のHTML要素とは異なり、DOM内に直接的な情報として存在しない
- スクリーンリーダーがcanvas要素の内容を認識できない
キーボード操作のサポートが困難
- canvas要素で描画されたオブジェクトに対するキーボード操作をサポートするためには、描画されたオブジェクトをJavaScriptで管理し、フォーカスの管理やイベントハンドリングを手動で実装する必要がある
- キーボードユーザーがどのオブジェクトにフォーカスしているかを視覚的に示すためには、canvas上で特別な処理を行う必要がある
ぱっと思いつくだけでも、解決しなければいけない課題がたくさんあるようです……。
※canvas要素で2Dのグラフなどを表示する場合にも、アクセシビリティについて意識して実装を行う必要があります。ただ、今回想定しているリッチでインタラクティブなビジュアルやアニメーションの表現とは違い、aria-label属性などで比較的シンプルに対応することが可能です。
canvas要素でアクセシビリティを実現するための解決策の検討
大前提として、HTML Standardで以下のように述べられているように、なんでもかんでも<canvas>内で表現しないことが大切です。
より相応しい要素が可用であるときは, 文書内に canvas 要素を利用するべきでない。 例えば、 ページの見出しを描画するために canvas 要素を利用するのは不適切である — 見出しの呈示をグラフィック的に目立たせたい場合、 適切な要素(概して h1 )を利用してマークアップした上で, CSS でスタイルをあてがい, shadow ツリーなどのサポート用技術を利用するべきである。
その上で、canvas要素の中でテキストを表示する方法で、アクセシビリティをある程度実現できる方法があるのか検討/検証していきます。
canvas要素でアクセシビリティをある程度担保しつつ、テキストの表示を行う方法の検討
canvas内でthree.jsを用いてテキストコンテンツを表現する方法は多岐にわたります。
以下は three.js docs:Creating text 内で紹介されている7つの方法です。
- DOM + CSS → 後述
- Use CSS2DRenderer or CSS3DRenderer → 後述
- Draw text to canvas and use as a Texture(テクスチャ画像を使ってテキストを描く)
- Create a model in your favourite 3D application and export to three.js(好きな3Dアプリケーションでモデルを作成し、three.jsにエクスポートする)
- Procedural Text Geometry(three.jsのTextGeometry機能を使って3Dのテキストを生成する)→ Sample
- Bitmap Fonts (Three-bmfont-textというプラグインを使ってテキストをレンダリングする)→ Sample
- Troika Text (troika-three-textというプラグインを使ってテキストをレンダリングする)→ Sample
3~7の方法に関しては、ただ単にcanvas要素内でのレンダリングを行っているだけなので、canvas要素が抱えるアクセシビリティの課題の解決が難しそうです。
それでは、1と2にの方法について軽く掘り下げていきます。
DOM + CSS
three.js docsで提案されているのは、テキスト要素をHTMLで準備し、他の要素より上のレイヤーで重ねて表示する方法です。
HTMLが使用できるので、一般的なサイトのようにアクセシビリティ対応はできますが、単純に重ねて表示しているだけで、これだけだとcanvas要素の中身と何か連携して動いたりしているわけではありません。
DOM+CSSのサンプル
Use CSS2DRenderer or CSS3DRenderer
次に提案されている方法は、three.jsのレンダラーであるCSS2DRenderer/CSS3DRendererを用いる方法です。three.js docs:Creating text では、下記のように説明されています。
これは 1 と似ていますが、これらのレンダラーを使用すると、要素をより緊密かつ動的にシーンに統合できます
コードサンプルを参考に、実際にページを作成してみました。
マウスやトラックパッドでぐりぐり視点を動かせるので、ぜひ試してみてください!
https://sample-css3drenderer.kakunin.dev/css3drenderer/
guest / X2wDhKTC
(くまさんと家の3Dモデルは、『ミニチュア作りで楽しくはじめる10日でBlender4入門』という本を参考に作成しています🐻)
下記はサンプルページのスクリーンショットです。
くまさんの横の吹き出しの部分は下記のようなシンプルはHTMLでできています。
<button id="js-modalbtn" class="c-spot" data-micromodal-trigger="bearmodal" type="button">
🧡
</button>
コードを見てわかる通り、クリックできるボタンになっていて、これがモーダルを開くトリガーになっています。
また、canvas要素内の視点を変更しても、このボタン(+開いたモーダル)の位置が3D空間内を追従することがわかると思います。
このボタンの要素に対してCSS3DRendererというレンダラーを用いてDOM要素を3D空間に擬似的に配置し、canvas要素と連動させて動かすことに成功しています🎉
この方法を用いれば、アクセシビリティの対応をしつつDOM要素を構成し、canvasと紐づけて動かすという流れで組み立てることが可能になります。
3Dオブジェクトに対してのキーボード操作や、代替テキストが付与できるようになったわけではないので、この方法でcanvas要素のあらゆるアクセシビリティ対応が可能になるわけではないのですが、解決策の一つとして使える方法だと考えています🎉
※ちなみに、右上の丸で囲んであるbackボタンは、上で説明したDOM+CSSの仕組みで表示しています。
※CSS2DRendererに関しては、CSS3DRendererと仕組みが似通っているのでサンプルは割愛します。
React Three FiberとReact Three A11yによる3Dコンテンツのアクセシビリティ向上
React Three Fiber(以下R3F)という、Three.jsをReactで使用するためのライブラリがあります。 Three.js をReactコンポーネントとして扱えるようにするもので、素のThree.jsより直感的にコードが書け、現状R3Fを用いることで制限される機能もなく、大変よくできたライブラリだと思っています。(個人の感想です)
R3Fについて調査/検証していると、R3F使用時にアクセシビリティを向上させるためのライブラリ、React Three A11yというものに出会いました。
フォーカスやタブ操作、スクリーンリーダーのサポートなど、課題として挙げていた項目が解決できる、と説明されています。
実際にサンプルコードを動かしてみました。
サンプルを動かしただけなので、このライブラリの全ての機能を検証できているわけではないのですが、3Dのオブジェクトに対してtab操作やhoverが効いていることがわかると思います。
ドキュメントを読んだ感じだと、ある程度のアクセシビリティ対応は網羅している印象で、現状最善の解決策であるように思いました。
Reactが使える案件であれば、導入を検討してみても良いかもしれません。
まとめ
今回はcanvas要素についての調査のまとめと、three.jsのCSS3DRenderer、React Three A11yを使ったアクセシビリティ対応について紹介しました。
canvas要素における3D表示についてのアクセシビリティ対応は一癖ありますが、実現したいことに応じて手順を選定し、柔軟に対応していくことが大切です。
今後もより良い対応方法について、追求していきたいと思います!