
HTML
イベント
マガジン
技術ブログ
こんにちは。ラクスのフロントエンド推進課の亀ノ上です。 Webアクセシビリティは、2022年のチームの課題棚卸しで私が挙げたテーマです。その後もR&Dの取り組みとして続けてきましたが、期日のある機能開発と並べると優先順位は後ろになり、着手には至っていませんでした。 今回、エンドユーザー向けの公開画面を持つ機能の開発で、Webアクセシビリティが要件になりました。対応を進める中で作ったのは、Webアクセシビリティを向上させる仕組みではありません。「どこが直せるのかを、プロダクトに手を入れずに知る」ためのレポート作成ツールでした。 この記事は、ツールの設計判断と、AIにどこまで任せられるのかが見えたところまでの記録です。同じようにWebアクセシビリティの向上に着手できずにいる方の判断材料になればと思います! アクセシビリティが後回しになる構造 取り組みが動き出したきっかけ プロダクトにlintを入れなかった理由 ツールの構成とAIの担当範囲 ルールの絞り込み基準 3リポジトリに回して分かった傾向 AIに改善を頼んで返ってきたコード AIが指摘を消す方向に向かう理由 次の課題はインプットの設計 今回の学びと、これから アクセシビリティが後回しになる構造 まずお伝えしたいこととして、社内で取り組みを提案してこなかったわけでも、提案が否定されたわけでもありません。工数を理由に断られるというより、やるのはいいけど機能開発が優先、となって結局稼働が取れず、未着手のままになる…というのが近い状況でした。 Webアクセシビリティは、「重要だが必須要件ではない」という位置に置かれがちです。期日のある機能開発と並べれば優先度は下がります。その判断自体は自然かもしれませんが、毎期同じ優先度となると、チームは着手しないまま次の期に入ってしまいます。 取り組みが動き出したきっかけ 要件になった機能( AI-FAQ機能 )は、エンドユーザー向けの公開画面を持っています。管理画面でコンテンツを作り、それを外部のエンドユーザーに公開します。ラクスのプロダクトの多くはバックオフィス業務を担う管理画面です。そこに、利用者を契約企業の担当者に限定しない公開画面が加わることになります。 Webアクセシビリティが要件になった理由は、どんな環境で使われるか分からない画面で、読み上げに対応していない、キーボードで操作できない、というような状態が、そのまま「使えない人がいる」ことにつながるからです。 要件になれば、最初にやることは現状の確認です。どの画面のどこが基準を満たしていないのかが分からなければ、直す範囲も、かかる工数も見積もれません。 注意すべき点として、Webアクセシビリティの確認はすべて自動チェックに任せられるわけではありません。自動チェックで検出できるのは一部で、残りは実際の画面を操作しながら確かめることになります。 自動チェックで分かる部分に関しては、プロダクトが違っても同じ調べ方が通用することがあります。今回の取り組みでは、その部分だけを切り出して、担当プロダクト専用にしない形で作りました。フロントエンド推進課としても、各プロダクトがWebアクセシビリティをどこまで満たしているのかを一覧で把握したいというニーズがあったためです。 作成するにあたって、プロダクトに導入するのではなく、シンプルに知るためのツールにしたい...そう考えました。プロダクトに組み込むのではなく、静的解析を社内で決めた基準に合わせて横断的に回せるようにすることで、他のプロダクトも現状を知る足がかりになります。 プロダクトにlintを入れなかった理由 Webアクセシビリティ関連のlintは、プロダクトのリポジトリに入れるのが素直なやり方かもしれませんが、今回はそうしませんでした。理由は2つあります。 ひとつは、エラーが出ても解消の仕方が分からず、負担になることです。lintを入れても、ルールの意味が伝わらなければ違反は残ります。 この懸念は、lintの置き場所を変えるだけでは解けません。外から回しても、理由が分からなければ同じことです。理由をどう伝えるかは、このあとに説明します。 もうひとつは、プロダクトのコードにライブラリを追加すること自体に判断が必要になる点です。どのルールを有効にするかの選定、ライブラリのアップデート対応、チームでの運用の取り決め。どれも必要な検討ですが、これを終えるまで着手できないとすると、また「機能開発が優先」となります。 そこで作ったのが、任意のディレクトリを指定して実行するとレポートが出力される、スタンドアロンのツールでした。ツールを落としてきて、パスを指定して回すだけです。プロダクトのコードには手を入れません。 lintはプロダクトに入れず、外から回す。この段階で優先したのは、着手のハードルを下げることでした。 ツールの構成とAIの担当範囲 処理は3つの段階に分かれています。AIが関わるのは②からです。 段階 やること AIの関与 ① 検出 Vue向けのアクセシビリティlint(eslint-plugin-vuejs-accessibility)で違反を洗い出す なし ② 説明 違反を一覧化し、なぜ引っかかったのかを書いたレポートに変換する あり ③ 改善 レポートを渡して、改善されたコードを出力させる あり(ここで詰まりました) lintの出力は「このルールに違反しています」までしか教えてくれません。なぜ違反なのかを知るには、ルールのドキュメントを都度見に行く必要があります。この確認の手間が、修正に取り掛かるまでの時間を延ばします。そこで、違反箇所とその理由を読めるレポートに変換する部分にAIを使いました。レポートにはサマリーと、ファイルごとの違反ルール・違反箇所が載っています。 ここまでは特に難しくありませんでした。ドキュメントを参照しながら書かせるだけだからです。 どのルールを対象にするかは、3つの条件で絞り込んでいます。 WCAG 2.2 適合レベルAの達成基準に対応する 静的解析で検出できる プロダクト固有の実装に依存しない 2つ目の条件が、このツールの守備範囲をそのまま決めています。フォーカスの移動順序が画面の見た目と合っているか、読み上げの順序として意味が通るか、操作に応じた状態の変化が支援技術に伝わるかは、Vueのテンプレートを構文解析するだけでは判定できません。実際のDOMとスタイルを解決したうえでの検査や、ブラウザでの操作確認が要る領域です。解析対象も <template> の中に限っていて、スクリプト側のロジックに起因する問題は見ていません。このツールで違反が検出されなくても、WCAG 2.2 の適合レベルAを満たしたことにはなりません。達成基準を満たせていないところの一部を静的解析で検出できる、という位置づけです。 ルールの絞り込み基準 採用・除外の判断は単純です。そのルールをWCAG 2.2 レベルAの達成基準と照らし合わせただけで、独自の重み付けはしていません。 基準に当てはめるだけでは決まらないルールが2つありました。 ひとつはラベルに関するルールです。ラベル要素で入力欄を囲む暗黙的な関連付けは、HTML仕様上は有効です。しかし、暗黙的な関連付けは、ブラウザと支援技術の組み合わせによっては対応されていない場合もあるので、明示的な関連付けをルールに入れています。 もうひとつは、フォーカスできる要素に role="presentation" が指定されていることを検出する no-role-presentation-on-focusable です。ARIAの仕様上、フォーカスできる要素では presentation の指定自体が無視されるため、指定しても効きません。こちらは、プラグインの推奨セットにも入っていないルールであることと、手動でのテストでカバーすることを理由に、初期の対象からは外しました。 3リポジトリに回して分かった傾向 現時点でツールを回したのは3つのリポジトリです。件数の集計はしていませんが、傾向は出ました。 違反が目立ったのは、プロダクト独自のUIコンポーネントでした。共通コンポーネント側で違反が少ないのは、そこがアクセシブルだからではなく、マークアップの実装がデザインシステム側にあって、このlintが見るプロダクトのテンプレートには現れないからです。デザインシステムを持っている組織なら、まずプロダクト独自のUIから見るのがよさそうです。 AIに改善を頼んで返ってきたコード レポートの出力までは問題なく動きました。 そのレポートをAIに渡して「アクセシビリティを改善して」と指示すると、lintのエラーが出なくなるコードが返ってきました。エラーは消えます。ただ、直してほしかった方向は違っていました。 具体例を2つ挙げます。いずれもVueのコードです。 例1: alt のない画像 < img : src = "logo" /> alt 属性がないため、スクリーンリーダーによってはファイル名などが読み上げられることがあります。AIが返してきたのは以下のコードです。 < img : src = "logo" alt = "" /> alt="" は「この画像は読み上げる必要がない」という意味を持つ書き方のひとつです。そのためlintは確かに通ります。 ただ、 alt に何を書くかは、その画像の用途と周りの文脈で決まります。ロゴのすぐ横に同じ内容のテキストが置かれているなら、二重に読み上げさせないために alt="" が適切な場合もあります。この例では、そうしたテキストがなく、画像だけが情報を担っているので、読み上げる必要があります。 < img : src = "logo" alt = "ラクス" /> 指摘を消すだけなら alt="" が最短です。ただそれを選ぶと、ロゴが伝えている情報は読み上げられなくなります。lintのエラーを消す方法は複数あり、どれを選ぶかで結果が変わります。 例2:クリックできる span 多かったのは、こちらのパターンです。元のコードはこうでした。 < span tabindex = "0" @click= "handleClick" > {{ text }} </ span > span はロールを持たない要素なので、支援技術に「操作できる要素」として伝わりません。キーボードイベントのリスナーもないため、EnterやSpaceで実行できない可能性があります。 AIが返してきたのは、次のコードです。 < span role = "button" tabindex = "0" @click= "handleClick" @keydown.enter.prevent= "handleClick" @keydown.space.prevent= "handleClick" > {{ text }} </ span > 指摘は消えます。ロールが付き、EnterとSpaceでも実行できるようになりました。支援技術からは操作できる状態ですが、以下のようなコードを期待していました。 < button type = "button" @click= "handleClick" > {{ text }} </ button > button を使えば、ロールもフォーカスもキーボード操作も標準で付いてきます。AIが出したコードは、 button が最初から持っているものを属性とイベントハンドラで組み立て直したものです。差が出るのは動く・動かないではなく、以後そのコードを触る人が同じ組み立てを維持できるかどうかです。 AIが提案したコードは、目視で確認して判定しています。多かったのは、セマンティックな要素を検討してほしい場面で、属性の追加で対応されてしまうパターンでした。 2つの例は性質が違います。例1では読み上げるべき情報が失われています。例2のほうは、主要な操作自体はできるようになっています。共通しているのは、lintのエラーを消す方法が複数あるなかで、元のコードを大きく変えない方法が選ばれたことです。指摘を消すことが目的になると、この選び方になるのだと思います。 AIが指摘を消す方向に向かう理由 原因は2つあると考えています。ひとつは検証のできない仮説ですが、もうひとつは今回の作りから直接たどれるものです。 仮説のほうは、AIが学習しているコードの側に原因があるのではないかと考えています。世の中にはアクセシブルではないコードが溢れていて、だからこそAIはそれらのコードをアウトプットとして出してくる。 span にロールを付けて操作できるようにしたコードは、実際のWebでも見かけます。ただ、モデルがそのコードを選んだ理由が学習データの偏りにあるのか、元のコードとの差分を小さくしようとした結果なのかは、外からは切り分けられません。 直接たどれるほうの原因は、こちらが渡している情報です。レポートに入っているのは、引っかかった箇所のコードと、その理由だけです。そのUIが何をするコンポーネントなのか、周りのコードとどう関係しているのかは入っていません。 alt の例がそのまま当てはまります。その画像がロゴなのか、本文の理解に必要な図なのか、単なる飾りなのかは、ファイル名とタグだけでは決まりません。文脈を見ないと決められない判断を、文脈なしで求めていました。代替テキストに何を書くかは、そのコンテンツを作った人が何を伝えたいかで決まります。そこはAIには判断できません。違反箇所のコードとlintの結果だけでは、その材料がありません。 これはWebアクセシビリティに限った話ではありません。静的解析の指摘をAIに直させるとき、渡しているのが「違反したルール」だけであれば、指摘を消すことが目的になります。検査が通ることと品質が上がることは別です。AIの出力がどちらに寄るかは、違反の条件だけを渡すのか、そのコードが何をするためのものかまで渡すのかで変わります。 次の課題はインプットの設計 ここから先は、まだ結果が出ていません。現時点の仮説は2つあります。 セマンティックな要素を使うことを優先させる WAI-ARIAの仕様を確認させる どちらも、属性で辻褄を合わせる方向に行かせないための指示です。ただ、指示文に書くだけで足りるのか、参照する資料まで渡す必要があるのかは、まだ検証していません。 ARIA Authoring Practices Guide(APG)のような、「このパターンはこうマークアップする」という指針が示されたガイドを参照させる案もありますが、これも着手前です。毎回ガイド全体を読ませるのは非効率なので、lintのルールに関連するAPGの箇所をリファレンスとして持たせる形も考えられそうです。 AIに任せられる範囲は、渡せる情報をどこまで設計できるかで決まります。今回の設計では、lintによる検出と、AIによる説明までは成立しました。改善まで任せようとすると、同じ情報だけでは足りませんでした。 今回の学びと、これから 今回の取り組みで得た学びのひとつは、AIによるWebアクセシビリティ向上の自動化は難しい、ということです。最終的に人間のレビューは必要で、だからこそ適切に判断できるように、Webアクセシビリティの知識をこれからもつけていきたいと考えています。 AIに任せる範囲を広げるほど、出てきたものを正しいと判断できる人が必要になります。Webアクセシビリティのように、ルールを通すことと、目的を果たすことがずれやすい領域では、その差が出やすくなります。 次は他プロダクトへの横展開ですが、その前にやることがあります。広げる前に、まず担当プロダクトのチームに展開して、誰でも対応できる運用にできるかを確かめます。ここが目の前のハードルです。 最後に、この記事の持ち帰りを4つに整理します。 Webアクセシビリティの向上に着手できていないなら、コードを直すところから始める必要はないかもしれません。まず「どこに問題がありそうかを知る」ところからなら、小さく始められます。 現状把握を始める段階なら、プロダクトにlintを組み込む判断を待たず、外から実行する方法も選べます。 デザインシステムを持っているなら、静的解析の指摘はプロダクト独自のUIに集まりやすくなります。探し始める場所の目安になるかもしれません。 検出はlintに、違反理由の説明はAIに任せられました。改善まで任せるなら、何を渡すかを設計する仕事が人間側に残ります。 直接コードの修正ができなくても、Webアクセシビリティを前に進めるアプローチはいろいろあると思います。思ったように取り組めずにいる方にとって、何かしらの参考になれば幸いです。
初めてブログを書きました。キクと申します。 普段はPower Platform関連の業務対応をしているエンジニアです。 今回は私がPower Automateを触り始めたころに苦戦したフローについて解説します。その内容は、
Notebook Enterprise APIでできることの振り返り 詳しくは、前回の記事を参考いただくとして、Notebook Enterprise APIでできることは主に3つのリソースに対する操作です。















