トピックを検索
警告も延長もないセッションタイムアウト
購入手続きがページを開いてから15分で利用者をログアウトさせ、警告がないか、スクリーンリーダーが読まないバナーだけで知らせるため、フォームに入力した内容がすべて失われます。
setTimeout(signOut, 15 * 60 * 1000) 問題
入力、読むこと、操作に時間がかかる人は、購入手続きの途中でログアウトされ、入力した内容を失います。気づける警告も、時間を延ばす手段もありません。
文具店の購入手続きで、配送先の住所とギフトメッセージを入力します。利用者はログインしていて、この店はサーバーへの最後のリクエストから15分で利用者をログアウトさせます。フレームワークの例からそのまま写した、セキュリティの既定値です。フォームへの入力はサーバーに何も送らないため、文章を書いている間も時計は進みます。15分になると、ページはログイン画面へ移ります。「セッションの有効期限が切れました」。制限があることも、それが近いことも、ページは何も伝えておらず、住所もメッセージも消えています。サーバー側の制限しかないサイトも多くあります。画面では何も起きず、「次へ」を押したときにフォームが失われます。
警告を出すサイトもあります。終了の2分前に、画面の上に「ログインを続ける」ボタン付きのバナーが現れます。修正に見えますし、気づいた、画面が見えるマウスの利用者には役に立ちます。しかし、バナーはページの最後に追加され、フォーカスも移らず、読み上げもされません。スクリーンリーダーの利用者には何も聞こえず、フォームを拡大している画面拡大ソフトの利用者には見えず、キーボードの利用者はすべての入力欄とフッターのリンクをTabで通過しないとボタンに届きません。
達成基準2.2.1「タイミング調整可能」は、コンテンツが設定するすべての時間制限を対象にしています。サイト自身のサーバーが終わらせるセッションも含まれます。対象外になるのは、ブラウザーやネットワークのように、コンテンツが制御できない制限だけです。それぞれの制限について、利用者が出会う前に解除できるか、既定の10倍以上に調整できるか、時間切れの前に警告して、簡単な操作で20秒以上の猶予のうちに延長でき、それを10回以上繰り返せる必要があります。例外は三つです。オークションのようなリアルタイムのイベント、その活動に欠かせない制限、20時間より長い制限です。
一つ目の購入手続きは、どれも満たしていません。二つ目は警告していますが、描いているだけです。2.2.1は警告の出し方を定めていませんが、警告は、警告する相手に届く必要があります。スクリーンリーダーが読まず、画面拡大ソフトの視野の外にあり、キーボードではほかのすべての後でしか届かない警告では、その人たちは予告なしに同じ締め切りを迎えます。この警告についてのW3Cの達成方法SCR16は、ブラウザー自身の確認ダイアログを使っていて、誰もがすぐにそれに出会います。
15分が長いか短いかは、フォームの入力のしかたによって変わります。スイッチで打つギフトメッセージや、手紙と照らし合わせて確かめる住所は、すぐにそれ以上かかります。そして、時間がより必要な人ほど、フォームが空になったときに失うものが大きく、時間のかかる部分を二度やることになります。スマートフォンでは、入力中はスクリーンキーボードがページの見える範囲を狭め、画面の上に固定したバナーがその範囲から外れることがあります。
10グループ中4グループに影響
- 全盲 (影響あり)
- 弱視 (影響あり)
- 色覚 (影響なし)
- ろう (影響なし)
- 難聴 (影響なし)
- 発話 (影響なし)
- 手の操作 (影響あり)
- 届く範囲・力 (影響なし)
- 認知 (影響あり)
- 光過敏 (影響なし)
- 手の操作が限られる スイッチ、ヘッドポインター、スクリーンキーボード、音声操作での入力にはずっと長い時間がかかり、配送先とギフトメッセージだけで15分を超えることがあります。ページは文の途中でログアウトさせます。
- 言語・認知・学習の能力が限られる 読むのがゆっくりな人、一つひとつ見直す人、カードや住所を探しに席を外した人は、作業の途中で制限に達し、空のフォームからやり直すことになります。
- 視覚を使わない スクリーンリーダーの利用者はフォームを進むのに時間がかかり、画面の上に描かれるだけの警告バナーは読み上げられません。最初に聞こえるのはログイン画面です。
- 視覚が限られる フォームを拡大している画面拡大ソフトの利用者には、画面の上のバナーが見えず、視野の外にある間にページを失います。
制限はスクリプトのタイマーやサーバーのセッション設定の中にあり、どちらもスキャンが読むページには現れません。警告がある場合も、それが出るのは13分後で、スキャンはとうに終わっています。axeが報告するのは、この失敗の古い形、遅延を付けてページを再読み込みしたり別のページへ移したりする <meta http-equiv="refresh"> で、W3Cの失敗例F40とF41に当たります。この診断では、カウントダウンを表示しているページや、セッションの終了に触れているページも、人が確認するよう挙げます。しかし、ページが何も触れていない制限は見えません。AIアシスタントに「一定時間操作がなければ自動ログアウト」を頼むと、よく一つ目の購入手続きと同じタイマーを書き、警告を頼むと、読み上げられないトーストやバナーを隅に加えます。キーボード、スクリーンリーダー、画面拡大ソフトで、実際に時間切れまで待ってみて、初めて分かります。
試してみる
ギフトメッセージを書き換えてから時間を進め、15分の制限の前にお店が何をするかを確かめてください。
ウィンドウの上のデモ用の時計は、経過する時間の代わりで、お店の一部ではありません。入力がサーバーに何も送らないのと同じく、入力しても時計は戻りません。最後の2分は実際の時間で進みます。「問題2」では、Tabで警告に届くか試し、スクリーンリーダーの読み上げも確認してください。
問題あり 修正できますか?
スクリーンリーダーの読み上げ:
(制限の2分前まで進める)
修正方法
セッションを利用時間より長くするか、終わる前にすぐ目に入るダイアログで警告し、1回押せばログイン状態が続くようにします。
- 1時間制限は20時間より長くするか、利用者が解除できるようにするか、終わる前に警告する。
- 2制限を残すなら、終了の20秒以上前に警告し、1回の操作で、必要なだけ何度でも延長できるようにする。
- 3警告はフォーカスのある場所に出し、見えて、読み上げられ、最初に届くようにする。
警告なしでログアウトするセッション
// 最後のリクエストから15分でセッションを終えるapp.use(session({ secret: process.env.SESSION_SECRET, rolling: true, cookie: { maxAge: 15 * 60 * 1000 } }));ログイン状態を続けられる警告ダイアログ
// 同じ15分のセッション。どのリクエストでも更新されるapp.use(session({ secret: process.env.SESSION_SECRET, rolling: true, cookie: { maxAge: 15 * 60 * 1000 } }));app.post('/session/extend', (req, res) => res.sendStatus(204));ページは、利用者が何をしていても、読み込んでから15分でログアウトさせます。制限を解除する、延ばす、延長を求める方法はありません。フォームに入力した内容は、ページと一緒に失われます。
制限は残りますが、知らないうちに出会う人はいません。終了の2分前に showModal() がページの上に警告を開き、フォーカスを「ログインを続ける」へ移します。スクリーンリーダーはタイトル、残り時間、ボタンを読み上げることができ、画面拡大ソフトはフォーカスを追ってそこへ移り、キーボードの利用者はすでにボタンの上にいます。1回押すか、Escapeを押せば、サーバーのセッションが更新され、ページの時計も最初から数え直します。必要なだけ何度でもできます。ブラウザーはフォーカスを元の場所に戻すため、利用者はそのまま入力を続けられます。誰も答えなければ、これまでどおりセッションは終わります。共用のパソコンでは、それがこの制限の役目です。
どちらも2.2.1を満たします。どちらが合うかは、アクセシビリティではなく、セッションが何を守っているかで決まります。15分が誰も選んでいない既定値から来ているなら、セッションを20時間より長くします。誰も中断されず、作るものもありません。制限がセキュリティのためにあるなら、それを残して警告ダイアログを加え、自分たちの制限に合わせて時間を決めます。ダイアログ、数行のスクリプト、エンドポイントが必要ですが、本当に席を離れた人に対する保護は残ります。画面に描くだけのバナーは、どちらの場合も残さないでください。
制限に出会う前に解除できる方法でも満たせます。 長いフォームの最初に置く「時間を長くする」のチェックボックスや、ログイン時にセッションを20時間より長くする「ログインしたままにする」のチェックボックスは、出会う前に制限を解除するか、10倍以上に延ばせる方法で、2.2.1はこれを認めています。ただし、気づいて意味を理解した人にしか効かないため、セキュリティのための制限があるサイトでは警告も残します。
どれだけ前に警告するか。 20秒は最低限で、ほとんどの人がキーかスイッチを一つ押せるように選ばれています。スクリーンリーダーでダイアログを読む、目を離していて後から気づくといった場合は、もっと時間がかかります。2分にしても失うものはなく、ずっと多くの人に間に合います。警告はサーバーの制限から逆算します。ページ自体がリクエストを送る場合(住所の検索、下書きの保存など)は、そのたびにページの時計も数え直し、両方をそろえます。
残り時間。 修正のように、残り時間はダイアログの文で伝えます。毎秒減る時計を描いてもかまいませんが、aria-hidden="true" を付け、ライブリージョンには入れません。そうしないと、スクリーンリーダーがボタンの上で毎秒読み上げます。
利用者の操作から数える。 修正は、サーバーと同じく最後のリクエストから数えています。入力中の人にダイアログを見せたくないサイトは、入力の間もセッションを更新できます。たとえば入力イベントが続く間は1分に1回リクエストを送り、手が止まったときのためにダイアログを残します。
スリープと別のタブ。 制限を過ぎるまでスリープしていたノートパソコンは、警告を一度も出さないまま制限の後に目覚めます。スリープ中はタイマーが動かないので、タイマーが動いたときとページが再び表示されたとき(visibilitychange)に、Date.now() と制限が始まった時刻を比べます。制限を過ぎていたら、セッションがまだあるかサーバーに確かめ、なければページでそう伝え、入力した内容は残します。複数のタブを開いている場合は、答えたタブからセッションを更新し、ほかのタブのダイアログは BroadcastChannel などで閉じます。
入力した内容を残す。 警告があっても、見逃した人はフォームを失います。下書きをブラウザーかサーバーに保存し、再ログインの後に戻すのは2.2.1の範囲を超えます。それは2.2.5「再認証」が求めることで、別のトピックです。
時間付きの確保。 購入手続きの間に座席や在庫を確保するカウントダウンも、時間制限です。W3C自身の例では、すぐに売り切れることのあるチケットの2分間の確保を欠かせない制限として扱ったうえで、名前や支払い情報の入力など、できるだけ多くの手順を時間制限のある部分の外へ出しています。確保を延長できる場合は、「時間を延長する」ボタンの付いた同じ警告ダイアログで満たせます。カウントダウンを見せることは、調整できることではありません。ボタンのない隅の時計は、誰にも変えられない制限のままです。
修正にならないもの。 メッセージを書き込む前からページにあるバナーに role="alert" を付けておけば、メッセージは読み上げられますが、フォーカスはフォームに残り、ボタンはページの最後のままです。15分を60分にするなど、固定の制限を長くしても、警告なしに出会う人はいます。
AI コーディングアシスタントで修正しますか? このガイドを Markdown で取得、または全ガイドをコーディングエージェントで使う。
修正の確認
マウスを使わない5つの確認
確認方法: キーボード、スクリーンリーダー、ズーム
OS、ブラウザーと支援技術のバージョン、ビルド、実施日、各手順の実際の結果を記録してください。セッションの設定、ログインの流れ、警告を変更した際は、再度確認します。
制限
ここで扱うのは、セッションやページを終わらせる時間制限と、それを警告する一つの方法です。ひとりでに動く、流れる、更新される内容には、別の達成基準とガイドがあります。一時停止できない、流れる文字、カルーセル、アニメーションを参照してください。タイマーで消えるメッセージも2.2.1の時間制限で、こちらにもガイドがあります。読む前や元に戻す前に消えるトーストを参照してください。遅延付きのmeta refreshのように、タイマーでページを再読み込みしたり移動させたりすることも、別のトピックです。データが失われるまでの無操作の時間を伝えること、時間に頼らない手順を設計することは、それぞれAAAの別のトピックです。制限が本当に欠かせないものか、リアルタイムのイベントの一部かは、サービスを運営する人にしか判断できません。また、ひとりでに開くダイアログの扱いはスクリーンリーダーによって異なります。利用者が使っているもので警告を確認してください。
よくある問題を再現した学習用のサンプルです。実在のクライアントの診断結果ではありません。コードは出発点となる実装例のため、実際の製品でも確認してください。ここでは支援技術でのテスト結果は報告していません。
コードを更新しても、使いやすさを保つために
ガイドの内容を、コーディングエージェントやCIで使える開発ルールにまとめます。更新後は、キーボードとスクリーンリーダーで再テストし、問題が再発していないか確認します。