アクセシビリティ公開 約11分

検索件数の更新を知らせる:role statusの範囲と通知する時点

検索後の件数が画面では変わっても、読み上げでは気付きにくい場合に。空の通知領域を先に置き、検索した時点で短い結果文を更新します。フォーカスを動かす方法との違いと、実際の読み上げで確かめる項目を整理します。

この記事の目次
  1. 結果の全文ではなく、操作が終わったことを短く伝える
  2. 空の通知領域を、検索前からHTMLへ置く
  3. 入力するたびに通知せず、検索操作を区切りにする
  4. 通知領域が増える失敗と、読み上げが長すぎる失敗
  5. DOMの検査と、利用環境で聞く検査を二段階にする

検索欄でEnterを押すと一覧は短くなるのに、読み上げでは検索が終わったか分からない。毎回結果の見出しへフォーカスを移すと、次の検索語を入力する場所から離れてしまいます。検索位置を保ったまま、件数の変化を知らせる方法を考えます。

HTMLのformとDOM操作が分かる人向けです。架空の資料棚にある三冊をブラウザー内で検索します。通信、ページ遷移、入力エラーは扱いません。検索そのものの実装はsubmitを入口にする記事と共通ですが、今回は更新をいつ、どの領域から伝えるかに絞ります。

結果の全文ではなく、操作が終わったことを短く伝える

検索後に知りたいのは、処理が終わり、何件見つかったかです。タイトルをすべて通知すると、件数が増えた場合に長い読み上げとなり、次の操作を始めにくくなります。一覧は通常の文書として残し、通知は要約だけにします。

WAIのステータスメッセージの解説は、フォーカスを移さずに支援技術へ伝える情報を扱い、検索件数も例にしています。すべての更新を通知するのではなく、利用者の操作結果を理解するために必要な情報を選びます。

ここでは「『星』の検索結果は2件です。一覧を確認できます。」という一文を作ります。0件なら検索語を変更できる案内へ替えます。結果の各タイトルはその下の見出しから読み進められるので、通知文と同じ情報を何度も並べません。

空の通知領域を、検索前からHTMLへ置く

role="status"を持つ空の段落を先に置き、その中の文字だけを更新します。statusには暗黙にaria-liveのpoliteとaria-atomicのtrueの意味があります。MDNのstatusの説明に沿い、利用者の現在の操作へ割り込む強い通知は使いません。

politeは、支援技術が適切な時点で更新を知らせるための指定です。「必ず何秒後に話す」という時間の保証ではありません。aria-atomicは一まとまりとして扱う指定なので、数字だけが変わった場合でも「2」だけより意味の分かる文を領域に置きます。

次をstatus.htmlへ保存し、ブラウザーで開きます。JavaScriptが無効なら三冊の一覧は読めますが、検索欄は準備されないため無効のままです。

<!doctype html>
<html lang="ja"><head><meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>資料棚の検索通知</title>
<style>
* { box-sizing: border-box; }
body { margin: 16px; color: #222; font-family: sans-serif; line-height: 1.8; }
main { max-width: 560px; margin: auto; }
fieldset { border: 0; padding: 0; min-width: 0; }
input { width: 100%; font: inherit; }
button { font: inherit; margin-block: 12px; }
#status { min-height: 1.8em; overflow-wrap: anywhere; }
:focus-visible { outline: 3px solid #174ea6; outline-offset: 3px; }
</style></head><body><main>
<h1>資料棚を検索する</h1>
<p>架空の三冊を検索します。空欄なら全件を表示します。</p>
<form id="search">
<fieldset id="fields" disabled>
<label for="query">資料名</label>
<input id="query" type="search">
<button type="submit">検索する</button>
</fieldset>
</form>
<p id="status" role="status" aria-atomic="true"></p>
<h2>検索結果</h2>
<ul id="results"><li>星の地図</li><li>星の写真</li><li>川の観察記録</li></ul>
<noscript><p>検索にはJavaScriptが必要です。</p></noscript>
</main><script>
const records = ['星の地図', '星の写真', '川の観察記録'];
const form = document.querySelector('#search');
const query = document.querySelector('#query');
const status = document.querySelector('#status');
const results = document.querySelector('#results');
form.addEventListener('submit', event => {
  event.preventDefault();
  const keyword = query.value.trim();
  const matches = records.filter(title => title.includes(keyword));
  const items = matches.map(title => {
    const item = document.createElement('li');
    item.textContent = title;
    return item;
  });
  results.replaceChildren(...items);
  const subject = keyword === '' ? '全資料' : `「${keyword}」の検索結果`;
  const message = matches.length === 0
    ? `${subject}は0件です。検索語を変えてください。`
    : `${subject}は${matches.length}件です。一覧を確認できます。`;
  if (status.textContent !== message) status.textContent = message;
});
document.querySelector('#fields').disabled = false;
</script></body></html>

更新するのはresultsの子要素とstatusの文字です。statusの要素自体は置き換えません。検索語もタイトルもtextContentへ渡し、利用者の入力をHTMLとして組み立てない構成にしています。

aria-atomicを明示しているのは、一文をまとめて知らせる意図をコードでも読めるようにするためです。roleだけでも持つ意味を、別の通知方式として二重に追加しているわけではありません。aria-live="assertive"やrole="alert"を同じ場所へ足し、急ぐ通知へ変える必要はありません。

入力するたびに通知せず、検索操作を区切りにする

この例はinputイベントで検索しません。文字を編集中に件数の通知が次々と入ると、入力の読み上げと競合することがあります。submitを区切りとし、検索ボタンと入力欄のEnterを同じ処理へ通します。

同じ検索を繰り返して同じ文になる場合は、更新を追加しない方針です。空文字へ戻して時間差で入れ直すなど、再読み上げを強制する細工は入れません。支援技術が同じ内容を再通知するかは環境にもよるので、「毎回必ず話す」という完成条件にしないでください。

検索語を編集している間、表示中の結果は前に実行した検索のものです。statusにはその検索語も含むため、現在入力中の語の結果と取り違えにくくします。自動検索が必要な画面なら、入力途中の扱い、通知頻度、古い通信結果の不採用まで別に設計します。

通知領域が増える失敗と、読み上げが長すぎる失敗

第一の失敗は、検索のたびにstatus要素を作り、文を入れた状態でDOMへ追加することです。支援技術が更新を監視する前に内容が入るため、期待どおり通知されない場合があります。また古い領域が残ると、画面や読み上げに複数の結果が並びます。

修正は、完成例のように一つの領域を検索前から置き、中身だけを更新することです。検索前後で同じ要素が残り、role="status"が一つであることを開発者ツールで確認します。その上で実際の読み上げを試し、通知されるかを別に記録します。

第二の失敗は、検索結果のul全体へrole="status"を付けることです。件数を知りたいだけなのに、資料名の一覧まで通知対象になります。修正ではulから役割を外し、要約の段落だけへ戻します。検索後に聞こえる案内が短い文で、一覧は自分で読み進められることを確認します。

通知を出すためstatusへfocus()を呼ぶ方法も避けます。statusは通常の操作部品ではありません。入力欄でEnterを押した後も入力欄にとどまり、次の検索語を続けて入れられるかを確認してください。ページ遷移やエラー修正のためにフォーカスを移す設計は、今回の検索結果通知とは別の問いです。

DOMの検査と、利用環境で聞く検査を二段階にする

10〜20分の確認として、まずキーボードだけで検索します。Tabで欄へ入り、星を入力してEnter、海へ変えてEnter、空欄にしてEnterを順に行います。日本語入力の変換中ではなく、確定した後のEnterで試します。

条件 画面に残る結果 要約の内容
星 星の地図・星の写真 星の検索結果は2件
海 項目なし 0件、検索語の変更を案内
空欄 元の三冊 全資料は3件
同じ語を再検索 結果は変わらない 再通知を必須にしない

DOM上では件数、statusの数、フォーカス位置を調べられます。しかし、それだけで読み上げを確認したことにはなりません。使用するスクリーンリーダーとブラウザーの組合せを記録し、入力位置を保ったまま結果の要約を聞けるか、一覧全体が不必要に割り込まないかを確認します。利用できない環境は未確認として残します。

0件の文言を決める場合は空の一覧の案内の記事も参照できます。アクセシビリティの無料レッスンの操作確認と組み合わせ、見える更新、聞こえる通知、操作を続ける位置の三つがそれぞれ成立するかを記録してください。

TRY A LESSON

記事の内容を、課題で確かめる

操作とコントラストを確かめる練習 →

アクセシビリティの学習内容 →

記事についてのお問い合わせ

記載内容へのご質問や訂正のご連絡は、hello@junkbranding.comまでお願いします。

← 記事一覧に戻る