アクセシビリティを考慮したHTMLコーディングガイド
これ何なの?
もともと私が社内メンバー向けに書いていたドキュメントで、 UIパーツ毎のアクセシビリティを考慮したHTMLコーディングTips集です。
社内のドキュメント置き場に眠っていたものですが、知見として社外にも共有出来る内容だなと思ったのと、アクセシビリティをこれからやっていこう!という方の参考になればと思い共有させて頂きます。
※そもそもアクセシビリティって何なの?という方は、ウェブアクセシビリティ基盤委員会のサイトを見てみてください🔍
目次
- おすすめVSCode拡張機能
- 🕹ボタン
- 📷 画像
- 🔍 ナビゲーション
- 💻 フォーム
おすすめVSCode拡張機能
axe Accessibility Linter をインストールしておくとimgタグのalt忘れなど警告が表示されるので、アクセシブルでない書き方を未然に防げるので便利です!
🕹ボタン
buttun
タグを使いましょう。( input type="button"
はHTML4の時代のものなので非推奨 )
div
タグでボタンを実装している例があるかもしれませんが、 div
タグではキーボード操作でフォーカスが当たらないためNGです ❌
フォーカスが当たらない例
<div class="save__button" @click="saveBlog">保存</div>
フォーカスが当たる例
<button class="save__button" @click="saveBlog">保存</button>
アイコンのみのボタンの場合
ECのカートボタン(🛒)のようにアイコンのみのボタンに対して、スクリーンリーダーを利用する際は、適宜以下のように aria-label
属性でボタンの効果がわかるように説明文を加えるとさらに良いかもしれません。
↓ 以下のコード例だとフォーカスが当たり、「カート内のアイテムを表示、ボタン」と読み上げられます
<!-- アイコンのみのボタン -->
<button class="cart__button" @click="openCart" aria-label="カート内のアイテムを表示"></button>
📷 画像
img
タグには必ず alt
属性を設定しましょう!
alt属性の有無や設定値によるスクリーンリーダーの読み上げの違いは以下の通りです。
alt属性がない場合
- 「fuga.jpg image」と読み上げられます
<img src="images/fuga.jpg">
alt属性が設定されている場合
- 「フガの写真」と読み上げられます
<img src="images/fuga.jpg" alt="フガの写真">
alt属性が設定されているが、空文字の場合
- 読み飛ばされます
- それ自体に意味を持たないデザインや装飾目的の画像の場合は、空文字にして読み飛ばさせるのが良さそうです。
<img src="images/fuga.jpg" alt="">
alt属性の設定値を書く際のヒント
【参考書籍・リンク】
1. 画像と等価のテキストを書く
例えば、クレジットカード会社の企業ロゴなどは以下のようにロゴに書かれているテキストを alt
にも設定するのが良いようです。
<img src="images/credit/jcb.png" alt="JCB">
2. 繰り返しを避ける
地図のような画像の前後にキャプション・説明文がある場合は、それらと重複しない内容を指定するのが良いようです。
<div>
<img src="images/map.png" alt="エフ・ニッセイ・恵比寿ビルまでの地図です。地図に続いて詳細">
</div>
<p>〇〇駅から〇〇方面に乗り、「〇〇駅」で下車します。改札を出たら右に曲がり……</p>
🔍 ナビゲーション
マークアップする際は、 nav
タグを使いましょう。
nav
タグを使うことでスクリーンリーダーに対してセクションがナビゲーション ( navigation
) ロールを持つことを伝えることが出来ます。
navタグでナビゲーションをマークアップした際のスクリーンリーダーの読み上げの例
<nav>
<ul>
<li>
<nuxt-link
to="/">
ホーム
</nuxt-link>
</li>
<li>
<nuxt-link
to="/shop">
店舗情報
</nuxt-link>
</li>
<li>
<nuxt-link
to="/menu">
メニュー
</nuxt-link>
</li>
<li>
<nuxt-link
to="/information">
お知らせ
</nuxt-link>
</li>
</ul>
</nav>
ナビゲーション内で現在のページをスクリーンリーダーに伝えたい場合
現在のページに該当するメニュー項目には、 動的に aria-current="page"
を設定するようにすることで、スクリーンリーダーに現在のページであることを伝えることが出来ます。
<nav>
<ul>
<li>
<nuxt-link
to="/" :aria-current="isCurrentPage('') ? 'page' : undefined"
>
ホーム
</nuxt-link>
</li>
<li>
<nuxt-link
to="/shop"
:aria-current="isCurrentPage('shop') ? 'page' : undefined"
>
店舗情報
</nuxt-link>
</li>
<li>
<nuxt-link
to="/menu"
:aria-current="isCurrentPage('menu') ? 'page' : undefined"
>
メニュー
</nuxt-link>
</li>
<li>
<nuxt-link
to="/information"
:aria-current="isCurrentPage('information') ? 'page' : undefined"
>
お知らせ
</nuxt-link>
</li>
</ul>
</nav>
💻 フォーム
label
の for属性
を使って適切にフォームコントロール( input
要素)との関連付けを行いましょう。
参考: H44: テキストラベルとフォームコントロールを関連付けるために、label 要素を使用する
テキストフィールドの例
<label for="firstname">First name:</label>
<input type="text" name="firstname" id="firstname" />
ラジオボタンなどのグループ化された入力要素については以下を参照ください。
参考: H71: fieldset 要素及び legend 要素を使用して、フォームコントロールのグループに関する説明を提供する
スクリーンリーダーのユーザーに直前の操作によってバリデーションエラーが発生したことを伝えたい場合
aria-live="polite"
をエラーメッセージの要素に付与することで実現出来ます。
以下のUIの例では、バリデーションエラー発生時に上から順に「お名前を入力してください」「メールアドレスを入力してください」「お問い合わせ内容を入力してください」と読み上げられます。
参考: ARIA ライブリージョン
<form>
<div class="mb-12">
<Label for="name">
お名前 <span class="text-xs text-red-500">(必須)</span>
</Label>
<input
id="name"
v-model="name"
class="w-full px-3 py-2 placeholder-gray-300 border border-gray-300 rounded-md focus:outline-none focus:ring focus:ring-indigo-100 focus:border-indigo-300"
type="text"
placeholder="お名前太郎"
/>
<!-- エラーメッセージ部分 -->
<p
v-if="name.$anyInvalid"
aria-live="polite"
class="text-xs text-red-500 mt-3"
>
{{ name.$message }}
</p>
<!-- エラーメッセージ部分 -->
</div>
<!-- 中略 -->
</form>
Discussion