Web アクセシビリティとフェイルセーフ

公開日

Webアクセシビリティ Advent Calendar 2020(adventar.org)の3日目の記事です。

「フェイルセーフ」という言葉を聞いた事はあるでしょうか。フロントエンドやアクセシビリティの文脈では話題になる事は少ないのですが、サーバーサイドのセキュリティ、あるいは工業製品の設計ではよく聞かれる重要な概念です。

簡単に言うと、機器に何かしら異常が起こった際に安全側に倒す設計思想です。

工業分野におけるフェイルセーフ(鉄道の事例)

まずは工業製品の事例、それも分かりやすい原始的なシステムをひとつ紹介します。

オリジナル画像
写真1:腕木信号機の脇を走行するストーブ列車(津軽鉄道)

この画像は青森県のローカル私鉄、津軽鉄道の写真です。津軽鉄道といえば冬季に運転されるストーブ列車(tsutetsu.com)が有名ですね。

2両目の客車の脇に建っているのは信号機なのですが、鉄道黎明期の19世紀に発明された手動操作タイプで、今ではほとんど見られない形をしています。現物を見たことがない方でも、『きかんしゃトーマス』の番組などで目にしているかもしれません。

これは「腕木信号機」と言って、上端にある赤い羽根(矢羽根)の角度によって「停止」(赤信号に相当)か「進行」(青信号に相当)かを表します。コンピュータを用いた「電子連動」など存在しない時代に発明されたもので、各信号機から金属製のワイヤーが駅まで張られており、駅員による手動操作で信号を切り替えます。

では、そのワイヤーが断線するなどして操作不能になってしまった場合はどうなるでしょう。もしも断線前の状態のまま固まってしまう挙動だったら、青現示のまま赤に変更できず、衝突事故を招いてしまいます。そのため信号機におもり(重錘)の機構を付けて赤信号の状態を「定位」とし、断線時は重力で自動的に赤の状態に戻るようになっています(上記の写真で客車の窓の高さあたりに付いている黒い円形の物体がその重錘です)。このように「地球の重力」という、故障や経年劣化の心配のない自然原理も活用して列車運行の安全が確保されてきました。

Web におけるフェイルセーフ

これを Web に置き換えるとどうでしょうか。 Web 空間は人間が作りあげたものなので自然災害は起こりませんし、どんな最悪な事態になっても直接の死亡事故が原理的に発生しません。なんという平和な世界なのでしょう。

一方で、現実世界では何か困ったことがあれば係員や周囲の人々が手助けしてくれる可能性があるのに対して、 Web 閲覧は基本的には孤独なもので何かあってもその場でのヘルプは期待できません。トラブルの原因がブラウザの設定に起因していた場合、サイト運営者に連絡したとしても原因の特定すら難しいかもしれません。

Web におけるアクセシビリティとは、そのような困った事態を極力少なくするために必要なことだと私は考えています。しかしそれをゼロにすることは困難です。そんなアクセシビリティの考慮から外れたケースが発生しても、フェイルセーフの考え方に則ったサイト設計がされていれば最悪の事態は防げるでしょう。

ユーザビリティとアクセシビリティとフェイルセーフ

Web アクセシビリティの説明でよく「ユーザービリティとアクセシビリティの違い」について語られることがありますが、そこにさらにフェイルセーフも加えてみます。

JIS Z 8521:2020「人間工学-人とシステムとのインタラクション-ユーザビリティの定義及び概念」では、ユーザービリティの定義を次のように定めています。

3.1.1 ユーザビリティ(usability)

特定のユーザが特定の利用状況において,システム,製品又はサービスを利用する際に,効果,効率及び満足を伴って特定の目標を達成する度合い。

JIS Z 8521:2020 - 3.1.1 ユーザビリティ(usability)

たった一文の中に「特定の」という表現が3回も出てくるのがおもしろいですね。

同じ JIS Z 8521 ではアクセシビリティについての定義もされています。

3.2.2 アクセシビリティ(accesibility)

製品,システム,サービス,環境及び施設が,特定の利用状況において特定の目標を達成するために,ユーザの多様なニーズ,特性及び能力で使える度合い(ISO 9241-112:2017 3.15 参照)。

JIS Z 8521:2020 - 3.2.2 アクセシビリティ(accesibility)

ユーザービリティの定義と比較すると「特定の利用状況」「特定の目標」は同じですが、「ユーザ」について「特定」ではなく「多様」が用いられている違いがあります。また、 6 章ではもう少し詳しい解説があります。

アクセシビリティのために設計する狙いは,対象とする母集団をより大きくすることである。ひいては,より多様な利用状況において,より多くの人々にとってアクセシビリティが高い製品,システム,サービス,環境及び施設を作ることである。

JIS Z 8521:2020 - 6.6.2 アクセシビリティ

このように、ユーザービリティが特定の利用ケースを想定したものに対して、アクセシビリティとはよりマクロな視点でさまざまな利用ケースを考慮したものと言えます。しかし、現実的にはすべてのケースを考慮するのは難しいので、さらにその根底としてフェイルセーフな状態を確保することが現代の Web に必要なことだと考えます。

フェイルセーフの定義は、工業分野では例えば JIS E 3013「鉄道信号保安用語」で

フェールセーフ 装置が故障した場合でも安全側状態になり,危険側に動作しないこと。

JIS E 3013:2001 - 3. a) 一般用語 1015

とされています。もう少し Web 寄りのものだと、 ISO/IEC 2382:2015(www.iso.org) でコンピュータセキュリティ分野における定義があります。

failsafe

<computer security> pertaining to avoidance of compromise in the event of a failure

ISO/IEC 2382:2015

failsafe operation

operation of a computer system such that in case of failure of a component, the probabilities of loss of equipment, damage to equipment, and harm to personnel are reduced

ISO/IEC 2382:2015

これらを簡潔にまとめると以下のようになります(かなりの意訳)。

ユーザビリティ
特定の利用ケースに対して使いやすさを追求するもの
アクセシビリティ
閲覧環境や障害の有無など、多様な利用ケースを考慮するもの
フェイルセーフ
想定外ケースで最悪の事態を防ぐ状態にするもの

HTML のフェイルセーフ

ここからはより具体的な事例を考えてゆきます。

さきほど、フェイルセーフで「最悪の事態を防ぐ」という表現を使いました。工業製品における最悪の事態とは死亡を含む傷害事故です。 Web の中でもセキュリティ分野においては DDoS によるサービス停止や個人情報流出などがありそうですが、アクセシビリティ視点では情報にアクセスできないことでしょう。

さて、 WWW の中核となるマークアップ言語である HTML は、デフォルトでフェイルセーフに相当する機構をいくつか備えています。

例えば <img> 要素の alt 属性は、画像にアクセスできない環境に対するフォールバック機構(html.spec.whatwg.org)ですが、同時にフェイルセーフとも言えます。しかしこれがフェイルセーフと言えるのは、 <img> 要素が古くから存在するものであり[1]、すべてのブラウザが alt 属性値の表示機構を備えているから故に成り立つものです。

その後の新しい要素は後方互換性を重視した書き方ができるようになっているものが多く、 <object> 要素や <video>, <picture> 要素などは要素の中身で代替表現ができるようになっています。このような仕様設計になっていることで、新しい技術を認識しない古いブラウザであってもフェイルセーフが働きます。

もしも仮に <video> 要素のフォールバック機構が <video src="movie.mp4" altimage="screenshot.png" alttext="○○をしている様子"/> のようなものだったら、 <video> 要素に対応していないブラウザでは何も表示されないことになってしまうので、それはフェイルセーフとは言えません。しかし HTML は極力そのようなことが起こらないように設計されているので、 Web 制作者にとっては「仕様どおりに書く」ことさえ心掛けていれば、仕様とブラウザのお陰で図らずもフェイルセーフが確保されると言えます。

CSS のフェイルセーフ

一方、 CSS や JavaScript はそうはいきません。どんなに仕様上正しい書き方だとしても Web ページが台無しになってしまうことが起こりえます。

「文字色を少しだけ薄めの黒にする」要件に対し、 :root { color: #111111 } と書かれてしまうことがあります。わずか24文字のコードですが、これは強力な破壊力を持っていて、環境によってはページ内のテキストがすべて読めなくなってしまう事態を招いてしまいます。

昨今のブラウザはデフォルト設定では白背景に黒文字なのが通例ですが、いくつかのブラウザには文字色と背景色をカスタマイズする機能がありますから、ユーザーの設定で任意の色に変更することが可能です。白背景は眩しいという理由で文字色と背景色を逆転させているとどうなるでしょう。スタイルシートが一切当たらない状況では文字色: #ffffff、背景色: #000000 になるところ、制作者スタイルシートの適用で文字色: #111111、背景色: #000000 になってしまいます。これではまともに文字を読むことができませんね。

配色設定はかなり昔からブラウザが備えている機能であり、「color と background-color はセットで指定する必要がある[2]」ことはスタイルシートが使われ出した頃から、いやそれ以前から「<BODY TEXT="" BGCOLOR=""> を片方だけ指定してはいけない」と言われていたと記憶しているのですが、どういうわけか最近このことは忘れ去られてしまった感があります[3]。 WCAG 2.1 達成方法集の F24: Failure of Success Criterion 1.4.3, 1.4.6 and 1.4.8 due to specifying foreground colors without specifying background colors or vice versa(www.w3.org) には失敗事例として掲載されており、 Firefox は最新のバージョン 83 でも配色のカスタマイズ機能を有しているので、決して過去の話ではないのですが……。

オリジナル画像
図1:1996年のブラウザ、 Internet Explorer 3 の「全般」設定
オリジナル画像
図2:2020年のブラウザ、 Firefox 83 の「配色」設定

そもそも、 Netscape Navigator も Internet Explorer も当初の描画エリアの背景色は灰色がデフォルトでした。今のように白色になったのはほんの20数年前のことであり[4]、また今後変わるかもしれないですし、いずれにしても「ブラウザの背景色は白」を前提にすべきではないでしょう。

オリジナル画像
図3:Internet Explorer 3 の起動画面(描画エリアが灰色)

さて、この問題をアクセシビリティ視点で見ると「color と background-color はセットで指定すべき(ことを制作者は知識として知っておく必要がある)」となります。しかし Chrome や Safari しか使わない人にとっては配色がカスタマイズできる事実を知らないかもしれませんし、こういった事例のすべてを把握せよというのも酷な話です。

フェイルセーフ視点ではどうでしょうか。 CSS はシンプルな構文の代償(?)としてエラー検知など複雑なことはできません。そうするとフェイルセーフが上手く働かないのではと思われるかもしれませんが、ブラウザにはスタイルシートの無効化機能が備わっています。仮に制作者の書いた CSS に不具合があったり、気に入らなかったりすれば、ユーザーにはスタイルシートを無効にして閲覧する手段が用意されているのです。また、ユーザースタイルシートを使って細かくカスタマイズすることも可能です。

オリジナル画像
図4:Firefox 83 のスタイルシート切り替えメニュー(「表示」 - 「スタイルシート」 - 「スタイルシートを使用しない」)

とはいえ、それらはユーザーに対してリテラシーを求めすぎな感じはありますし、モバイル系などでスタイルオフの機能を持たないブラウザも存在します。 CSS に関しては、結局のところフェイルセーフ機構にはあまり期待できず、アクセシビリティの知識を高めるという制作者の地道な努力が求められるでしょう。

JavaScript のフェイルセーフ

JavaScript も CSS のように、たった1行で破壊的なことが起こりえます。

「何かしらのデータをストレージに一時的に記憶する」要件に対し、 sessionStorage.setItem('foo', 'hoge'); と書かれてしまうことがあります。環境によってはこれだけで後続のスクリプト処理がすべて止まってしまいます。

具体的にはブラウザの設定で Cookie を無効にしていたり、あるいは保存容量が上限に達していたりする場合に DOMException が発生し、例外を受け止めることをしていないとそこで処理が止まってしまいます。MDN の Storage.setItem() 解説ページ(developer.mozilla.org)でも開発者は、setItem() で発生する可能性がある例外を常にキャッチするようにしてください。と <strong> も使って強調されていますね。

とくにここ数年、クライアントサイドレンダリング(CSR)方式により Web ページ全体が JavaScript が動作することに依存した作りになっているサイトが増えてきていますが、スクリプト途中で例外が発生すると「ページのコンテンツが表示されない(ユーザーは情報にまったくアクセスできない)」事態が発生してしまいます。

アクセシビリティの観点からは、 MDN でも解説されているように try - catch で囲むのが正しい解決策となるでしょう(アクセシビリティの観点というより、もはやただのバグ修正ですが)。しかし CSS の事例でも書いたように、そういう事前知識がないと対処できません。

フェイルセーフ視点だとこうなります。

  • JavaScript が動かなくてもコンテンツを閲覧できるように設計する(たとえ処理が途中で止まっても情報へのアクセス自体は阻害されない)
  • エラー発生を検知するシステムを組み込む

前者が理想的ですが、既に出来上がっているサイトだと抜本から見直す必要があり、すぐの改修は難しいかもしれません。

一方、後者の対策は新規制作時はもちろん、既存サイトへの挿入であっても大きな影響なく導入できるでしょう。具体的には window オブジェクトの error イベント(www.w3.org)を使うことで実現可能です。一例として、エラー発生時に発生箇所やエラーメッセージなどの情報をサーバー上に用意したエンドポイントに送信するサンプルを書くとこうなります。

window.addEventListener('error', (ev) => {
  const formData = new FormData();
  formData.append('location', location.toString());
  formData.append('message', ev.message);
  formData.append('filename', ev.filename);
  formData.append('lineno', String(ev.lineno));
  formData.append('colno', String(ev.colno));

  try {
    fetch(ENDPOINT, {
      method: 'POST',
      body: new URLSearchParams([...formData]),
    });
  } catch (e) {
    /* fetch() メソッドで例外(AbortError や TypeError)が発生した時の処理 */
  }
});

当ブログでもこれを基に実用化したクラス(saekitominaga.github.io)を組み込んでいますが、個人ブログレベルでも実際に運用してみると興味深いエラーレポートを受け取ることがあります。例えば、とある検索エンジンのロボットは通常のブラウザとはまったく異なるキャッシュ活用をしているようで、 ESModules の import / export を使用している場面でメソッド名を変更したところ、 import 先の変更内容がしばらく認識されずに結果としてエラーを吐く事象に遭遇したことがあります。こんなケースはいくらブラウザ上でテストをしたところで事前に発見するのは困難でしょう。しかし、すべてのエラーに対する受け皿を用意することで、実際のユーザー環境(ロボットを含む)でどんなエラーが発生しているかを把握し、対処することが可能になります。

工業製品のフェイルセーフでは事故を未然に防ぐことが原則なのに対し、この方法は少なくとも一度は事故(エラー)を発生させてしまうところに違いはありますが、技術的に可能な範囲、かつ現実的に導入可能な監視機構として、とくに JavaScript に依存したサイトでは検討に値するのではないでしょうか。

前提を捨て去ろう

ブラウザには多数の設定項目が存在し、ユーザーはそれをカスタマイズすることができます。スクリーンリーダーや点字ディスプレイも、 OS や外部機器を巻き込んだカスタマイズの一種と言えるでしょう。

わざわざデフォルトから設定を変更するのには理由があるはずで、 Web 制作者はその行為を尊重すべきです。しかしあらゆる使われ方をエンジニアに知識として求めるのは酷なものです。ブラウザが内包する設定項目だけでも単純に量が多すぎますし、 OS や拡張機能(アドオン)の設定が影響することもありますし、それらの組み合わせによってどんな作用が起こるかを把握するのも困難です。

そのためアクセシビリティを学び実践するにあたり、個々の知識を身に付けることも大事ですが、まずは「前提を捨て去る」ことが必要だと私は考えます。

  • PC ではマウスが使えるはずだ
  • 画像や動画が見えるはずだ
  • JavaScript の処理が最後の行まで動作するはずだ
  • Cookie が受け入れられるはずだ
  • レスポンスコード 301 や 303 ではレスポンスボディ(HTML)が表示される前にリダイレクトが実行されるはずだ
  • <a href> や <form> で遷移すればリファラーが送信されるはずだ
  • <iframe> を使えば別サイトのリソースを表示できるはずだ
  • スクリプトが動かない場合は <noscript> 内の記述が表示されるはずだ
  • color: red と書けば文字が赤くなるはずだ

こういった前提をしてしまう限り、その前提から外れた環境では必ず何かしらの不具合が発生してしまいます。そして多くの場合、不具合が発生している事実すら制作者の耳には届かないでしょう。

前提に対する策を網羅できないのが悪いのではありません。アクセシビリティのガイドラインとして有名な Web Content Accessibility Guidelines (WCAG) (www.w3.org)でも、序章にてこんなことが書かれています。

Note that even content that conforms at the highest level (AAA) will not be accessible to individuals with all types, degrees, or combinations of disability, particularly in the cognitive language and learning areas

Web Content Accessibility Guidelines (WCAG) 2.1 - 0.2 WCAG 2 Layers of Guidance(www.w3.org)

注意すべきなのは、最高レベル (AAA) で適合しているコンテンツでさえも、すべての種類、程度あるいは組合せの障害のある個人、特に、認知、言語及び学習の面において、アクセシブルではないということである。

Web Content Accessibility Guidelines (WCAG) 2.1 - 0.2 WCAG 2 ガイダンスのレイヤー(waic.github.io)

このように世界的なガイドラインですら、あらゆるアクセシビリティ面を考慮するのは困難だと言っています。なんだか絶望的な印象を与えてしまいそうですが、要は世界はコントロール不可能なほど多様だという当たり前の話なのです。

完全を目指すのが難しい現状に対して我々(Web 制作者)ができることはなんでしょうか。一つはできることから無理なく始めること。最初から WCAG のレベル AA を目指す必要なんてありません。

そしてもう一つがフェイルセーフの思想を持つことではないかと思います。工業製品でも Web においても、エンジニアの想定外の事故は必ず起こります。だからこそ想定外は起こるものと想定することがアクセシビリティ、すなわち「多様な利用ケース」を考慮する第一歩ではないでしょうか。

  • [1]1993年に公開された HTML ドラフト(www.w3.org)で既に定義されています。
  • [2]正確に言うと、 CSS の「継承」も利用して当該要素に color と background-color の両方が適用される書き方をすれば大丈夫です。 :root に対しては(指定するならば)常に両方を指定する必要があり、どちらか片方のみの指定をしてはいけません。
  • [3]実際に Firefox でテキスト色と背景色を反転させてブラウジングすると、多くのサイトで文字が読めない・読みにくいケースに遭遇します。残念なことに JIS X 8341-3 の等級AAに準拠していると謳っている中央官庁や自治体サイト、あるいはアクセシビリティに造詣が深いはずのエンジニア個人サイトでも珍しいことではありません。 W3C のサイト内にすらそういうコンテンツが存在するのはちょっとショックです。
  • [4]Internet Explorer はバージョン 4 から OS の配色(デフォルトの背景色が白)を使用するようになりましたが、色変更のカスタマイズ画面で「Windows の色を使用する」のチェックを外した時のデフォルト色は最後のバージョン 11 に至るまで灰色設定を貫いていました。