# フォーカス順の最後に回る、フローティングボタンとパネル

Source: https://easeweb.dev/learn/floating-order
Topics: ダイアログとオーバーレイ > フローティングボタンとそのパネルが、フォーカス順の正しい位置に来る (WCAG 2.4.3)
The fix: 浮いたボタンをその内容がある位置に書き、パネルをその直後に置きます。マークアップ上でシートをボタンの直後に置くか、ボタンがpopovertargetで開くポップオーバーにします。ポップオーバーなら、どこにあってもブラウザーがTabの順でボタンの次に置きます。開いたときにフォーカスをシートの中へ移す方法でも基準は満たしますが、シートからTabやShift + Tabで出ると、ページの最後へ移ります。
Test with: keyboard, screen reader
References: https://www.w3.org/WAI/WCAG22/Understanding/focus-order.html https://www.w3.org/WAI/WCAG22/Techniques/css/C27 https://www.w3.org/WAI/WCAG22/Techniques/failures/F85 https://www.w3.org/WAI/WCAG22/Techniques/client-side-script/SCR26 https://developer.mozilla.org/en-US/docs/Web/API/Popover_API/Using

よくある問題を再現した学習用のサンプルです。実在のクライアントの診断結果ではありません。コードは出発点となる実装例のため、実際の製品でも確認してください。ここでは支援技術でのテスト結果は報告していません。

## 場面

ツアー会社の予約ページが、スマートフォン向けにデザインされています。「旧市街ウォーキングツアー」「2時間、1人$25から」、写真、集合場所と「地図で開く」リンク、タップで開く3つの質問（「段差のないルートですか？」「雨の場合は？」「キャンセルできますか？」）、「128件のレビューをすべて読む」リンクが並び、フッターに「ヘルプセンター」「利用規約」「お問い合わせ」があります。ページを開いた時点から、画面の下に白いバーが浮いていて、「$25から」と「予約する」ボタンがあり、いつでも親指で予約できます。「予約する」を押すとバーのすぐ上にシートが開き、日付を選んで「次へ」へ進めます。

キーボード利用者がページを開き、見えている「予約する」へ進もうとTabを押します。フォーカスは代わりに「地図で開く」へ移り、続いて各質問、レビューのリンク、フッターの3つのリンクへ進みます。「予約する」は9回目のTabです。スクリーンリーダー利用者が最初から読むと、フッターまでページ全体を聞いた後で、ようやく「予約する、ボタン、折りたたみ」にたどり着きます。

開発者はこの問題に気づき、バーをマークアップの上へ、価格の後に移します。「予約する」は最初のTabになりました。ところが、もう一つの問題が残ります。Enterキーを押すとシートが開きますが、最初の日付へ進もうとTabを押すと、フォーカスは「地図で開く」へ戻ります。日付に届くのは、またページ全体の後、9回先です。

## 確認できる問題

バーもシートも、ページの最後、フッターの後に書かれています。親要素に切り取られないよう、予約ウィジェットやコンポーネントライブラリーが浮いて表示するものを置くことの多い場所です。CSSは画面の下に描きますが、Tabとスクリーンリーダーは見た目には従いません。マークアップの順にページを進み、マークアップの上ではバーとシートは最後です。マークアップの順序を画面上の順序に合わせる達成方法C27は、この食い違いを解消するものです。

達成基準2.4.3 フォーカス順序は、意味と操作を損なわない順序でフォーカスが移ることを求めています。バーはページの主な操作として最初から内容の手前に描かれ、スマートフォンではこれが唯一の「予約する」ボタンです。それなのにすべての後に来るため、キーボードとスクリーンリーダーの利用者は、ほかの人が1回のタップで届くものに、ページ全体を通ってたどり着くことになります。フォーカス順序は見た目の配置に従う必要はなく、2.4.3の解説も本文の後に書いたナビゲーションを適合する例に挙げているため、浮いた操作要素が最後に来てよいかどうかは、ページに対する判断です。ページの最後にある「ページ上部へ」ボタンやチャットの起動ボタンは事情が違います。ページの目的ではなく、利用者もそこにあると考えるためです。

シートも、失敗例F85のとおり同じ達成基準を満たしません。ボタンで開くダイアログやメニューに、フォーカスが移らず、次のTabでも届かない場合です。ボタンを移すと最初の問題は解消しますが、シートは最後に残るため、こちらの問題は残ります。F85のテストには後半もあり、そちらはこのシートも満たしています。Escapeキーで閉じると、フォーカスは「予約する」に戻ります。シートへ向かう途中、フォーカスはシートの後ろも通るため、見えなくなることもあります。

## 利用者への影響

ページが長いほど、バーもシートも遠くなります。写真のギャラリー、地図、十数件のレビュー、充実したフッターのある実際の予約ページなら、「予約する」まで数十回、日付までさらに同じくらいのTabが必要になることがあります。

## 自動チェックとAIの限界

一つひとつの部品に問題はありません。「予約する」は名前と`aria-expanded`を持つbuttonで、シートには見出し、凡例、ラベル付きの選択肢があり、どの操作要素にも到達できます。axeが報告することはありません。問題は順序にあり、ページがどの順序を意図しているかは人にしか判断できません。EaseWebの診断は、ウィンドウに固定された操作要素に、ページのフッターの後でしかTabが届かない場合を、確認が必要な項目として挙げるようになりました。「ページ上部へ」ボタンは最後にあってよく、チャットの起動ボタンとCookieバナーにはそれぞれ別の確認があるため、これらは除きます。2つ目の問題は検出結果として報告します。`aria-expanded`と`aria-controls`を持つボタンを、1ページにつき12個まで一つずつ開き、フォーカスがパネルの中へ移らず、次のTabでも届かないとき、そのパネルを報告します。開くことを伝えないボタンのパネルや、外部サービスのフレームの中にあるパネルは、引き続き手作業でしか見つけられません。ページの上に浮くバーやシートをAIアシスタントに頼むと、`overflow`や`z-index`の影響を避けるためにポータルや`document.body.append()`を使うことがあり、それが順序に何をもたらすかは説明されません。

## 修正前：フッターの後にあるバーとシート

```css styles.css
/* バーのための余白。ページの最後やフォーカスを覆わないようにする。 */
html {
  scroll-padding-bottom: 5rem;
}
body {
  padding-bottom: 5rem;
}
.book-bar {
  position: fixed;
  inset-inline: 1rem;
  bottom: 1rem;
  display: flex;
  align-items: center;
  justify-content: space-between;
  /* 高さ4rem、下端から1rem：確保した5remに収まる。 */
  height: 4rem;
  padding: 0 1rem;
  border-radius: 1rem;
  background: #fff;
}
.sheet {
  position: fixed;
  inset-inline: 1rem;
  bottom: 5.5rem;
  padding: 1rem;
  border-radius: 1rem;
  background: #fff;
}
```

```html index.html
<main>
  <h1>旧市街ウォーキングツアー</h1>
  <p>2時間、1人$25から</p>
  …
</main>
<footer>…</footer>
<div class="book-bar">
  <p>$25から</p>
  <button type="button" class="book-button" aria-expanded="false" aria-controls="booking">予約する</button>
</div>
<div class="sheet" id="booking" hidden>
  <h2>日付を選ぶ</h2>
  <form action="/checkout">
    <fieldset>
      <legend>日付</legend>
      <label><input type="radio" name="date" value="2026-06-13"> 6月13日（土）</label>
      <label><input type="radio" name="date" value="2026-06-14"> 6月14日（日）</label>
      <label><input type="radio" name="date" value="2026-06-20"> 6月20日（土）</label>
    </fieldset>
    <button type="submit">次へ</button>
  </form>
</div>
```

```js script.js
const button = document.querySelector('.book-button');
const sheet = document.querySelector('#booking');

function setOpen(open) {
  sheet.hidden = !open;
  button.setAttribute('aria-expanded', String(open));
}
button.addEventListener('click', () => setOpen(sheet.hidden));
sheet.addEventListener('keydown', (event) => {
  if (event.key === 'Escape') {
    setOpen(false);
    button.focus();
  }
});
// ページのほかの部分へ移ると閉じ、フォーカスのある所を覆わない。
sheet.addEventListener('focusout', (event) => {
  const next = event.relatedTarget;
  if (next && next !== button && !sheet.contains(next)) setOpen(false);
});
```

ボタン、その状態、閉じる処理、バーのための余白は、どれも正しく書かれています。間違っているのはバーの場所だけです。フッターの後にあるため、「予約する」は「地図で開く」、3つの質問、レビューのリンク、フッターの3つのリンクの後、9回目のTabです。シートはその直後にあるため、「予約する」に届けば、日付は次のTabです。

## 修正前：バーは移したが、シートはフッターの後のまま

```css styles.css
/* バーのための余白。ページの最後やフォーカスを覆わないようにする。 */
html {
  scroll-padding-bottom: 5rem;
}
body {
  padding-bottom: 5rem;
}
.book-bar {
  position: fixed;
  inset-inline: 1rem;
  bottom: 1rem;
  display: flex;
  align-items: center;
  justify-content: space-between;
  /* 高さ4rem、下端から1rem：確保した5remに収まる。 */
  height: 4rem;
  padding: 0 1rem;
  border-radius: 1rem;
  background: #fff;
}
.sheet {
  position: fixed;
  inset-inline: 1rem;
  bottom: 5.5rem;
  padding: 1rem;
  border-radius: 1rem;
  background: #fff;
}
```

```html index.html
<main>
  <h1>旧市街ウォーキングツアー</h1>
  <p>2時間、1人$25から</p>
  <div class="book-bar">
    <p>$25から</p>
    <button type="button" class="book-button" aria-expanded="false" aria-controls="booking">予約する</button>
  </div>
  …
</main>
<footer>…</footer>
<div class="sheet" id="booking" hidden>
  <h2>日付を選ぶ</h2>
  <form action="/checkout">
    <fieldset>
      <legend>日付</legend>
      <label><input type="radio" name="date" value="2026-06-13"> 6月13日（土）</label>
      <label><input type="radio" name="date" value="2026-06-14"> 6月14日（日）</label>
      <label><input type="radio" name="date" value="2026-06-20"> 6月20日（土）</label>
    </fieldset>
    <button type="submit">次へ</button>
  </form>
</div>
```

```js script.js
const button = document.querySelector('.book-button');
const sheet = document.querySelector('#booking');

function setOpen(open) {
  sheet.hidden = !open;
  button.setAttribute('aria-expanded', String(open));
}
button.addEventListener('click', () => setOpen(sheet.hidden));
sheet.addEventListener('keydown', (event) => {
  if (event.key === 'Escape') {
    setOpen(false);
    button.focus();
  }
});
// ページのほかの部分へ移ると閉じ、フォーカスのある所を覆わない。
sheet.addEventListener('focusout', (event) => {
  const next = event.relatedTarget;
  if (next && next !== button && !sheet.contains(next)) setOpen(false);
});
```

バーをマークアップの上へ、価格の直後に移しました。`position: fixed`により画面の下に描かれたまま、「予約する」は最初のTabになります。シートは元の場所、フッターの後に残っているため、シートを開いた状態で「予約する」からTabを押すと、シートの下にあることもある「地図で開く」へ移り、最初の日付に届くのは、質問、レビューのリンク、フッターの3つのリンクの後です。

## 修正後：内容と一緒のバーと、その直後のシート

```css styles.css
/* バーのための余白。ページの最後やフォーカスを覆わないようにする。 */
html {
  scroll-padding-bottom: 5rem;
}
body {
  padding-bottom: 5rem;
}
.book-bar {
  position: fixed;
  inset-inline: 1rem;
  bottom: 1rem;
  display: flex;
  align-items: center;
  justify-content: space-between;
  /* 高さ4rem、下端から1rem：確保した5remに収まる。 */
  height: 4rem;
  padding: 0 1rem;
  border-radius: 1rem;
  background: #fff;
}
.sheet {
  position: fixed;
  inset-inline: 1rem;
  bottom: 5.5rem;
  padding: 1rem;
  border-radius: 1rem;
  background: #fff;
}
```

```html index.html
<main>
  <h1>旧市街ウォーキングツアー</h1>
  <p>2時間、1人$25から</p>
  <div class="book-bar">
    <p>$25から</p>
    <button type="button" class="book-button" aria-expanded="false" aria-controls="booking">予約する</button>
  </div>
  <div class="sheet" id="booking" hidden>
    <h2>日付を選ぶ</h2>
    <form action="/checkout">
      <fieldset>
        <legend>日付</legend>
        <label><input type="radio" name="date" value="2026-06-13"> 6月13日（土）</label>
        <label><input type="radio" name="date" value="2026-06-14"> 6月14日（日）</label>
        <label><input type="radio" name="date" value="2026-06-20"> 6月20日（土）</label>
      </fieldset>
      <button type="submit">次へ</button>
    </form>
  </div>
  …
</main>
<footer>…</footer>
```

```js script.js
const button = document.querySelector('.book-button');
const sheet = document.querySelector('#booking');

function setOpen(open) {
  sheet.hidden = !open;
  button.setAttribute('aria-expanded', String(open));
}
button.addEventListener('click', () => setOpen(sheet.hidden));
sheet.addEventListener('keydown', (event) => {
  if (event.key === 'Escape') {
    setOpen(false);
    button.focus();
  }
});
// ページのほかの部分へ移ると閉じ、フォーカスのある所を覆わない。
sheet.addEventListener('focusout', (event) => {
  const next = event.relatedTarget;
  if (next && next !== button && !sheet.contains(next)) setOpen(false);
});
```

バーをマークアップ上で、それが繰り返す価格の直後に置き、シートをバーの直後に置きます。ほかは何も変わらず、`position: fixed`により、画面上ではどちらも同じ場所に描かれます。「予約する」はページの最初のTabです。シートを開いた状態で「予約する」からTabを押すと最初の日付へ、「次へ」の後のTabは「地図で開く」へ移ってシートを閉じるため、フォーカスのあるリンクがシートの下に隠れることはありません。日付からのShift + Tabは「予約する」へ戻ります。閉じている間は、`hidden`がシートを順序から外します。スクリーンリーダーで最初から読んでも、価格の後にバーが、その次にシートが読まれます。バーには達成方法C27、シートには、操作要素で表示する内容をその直後に置く達成方法SCR26を使っています。この方法は、`position: fixed`がウィンドウを基準にしていることが前提です。`transform`、`filter`、`contain`を持つ親要素があると、バーとシートはその親を基準に固定され、親要素の`z-index`によって後の内容がその上に描かれることもあります。親要素を確認してください。

## 修正後：内容と一緒のバーと、ポップオーバーのシート

```css styles.css
/* バーのための余白。ページの最後やフォーカスを覆わないようにする。 */
html {
  scroll-padding-bottom: 5rem;
}
body {
  padding-bottom: 5rem;
}
.book-bar {
  position: fixed;
  inset-inline: 1rem;
  bottom: 1rem;
  display: flex;
  align-items: center;
  justify-content: space-between;
  /* 高さ4rem、下端から1rem：確保した5remに収まる。 */
  height: 4rem;
  padding: 0 1rem;
  border-radius: 1rem;
  background: #fff;
}
.sheet {
  position: fixed;
  inset-inline: 1rem;
  bottom: 5.5rem;
  padding: 1rem;
  border-radius: 1rem;
  background: #fff;
  /* ポップオーバー本来の表示（ウィンドウの中央、内容に合わせた大きさ、枠線）を打ち消す。 */
  top: auto;
  width: auto;
  margin: 0;
  border: 0;
}
```

```html index.html
<main>
  <h1>旧市街ウォーキングツアー</h1>
  <p>2時間、1人$25から</p>
  <div class="book-bar">
    <p>$25から</p>
    <button type="button" class="book-button" popovertarget="booking">予約する</button>
  </div>
  …
</main>
<footer>…</footer>
<div class="sheet" id="booking" popover>
  <h2>日付を選ぶ</h2>
  <form action="/checkout">
    <fieldset>
      <legend>日付</legend>
      <label><input type="radio" name="date" value="2026-06-13"> 6月13日（土）</label>
      <label><input type="radio" name="date" value="2026-06-14"> 6月14日（日）</label>
      <label><input type="radio" name="date" value="2026-06-20"> 6月20日（土）</label>
    </fieldset>
    <button type="submit">次へ</button>
  </form>
</div>
```

```js script.js
const button = document.querySelector('.book-button');
const sheet = document.querySelector('#booking');

// ページのほかの部分へ移ると閉じ、フォーカスのある所を覆わない。
sheet.addEventListener('focusout', (event) => {
  const next = event.relatedTarget;
  if (next && next !== button && !sheet.contains(next)) sheet.hidePopover();
});
```

バーは前の方法と同じく価格の直後に移し、シートはフッターの後に置いたままにします。予約ウィジェットやコンポーネントライブラリーが、そこに置くことを譲らない場合です。代わりにブラウザーが、Tabの順でシートを次に置きます。ボタンが`popovertarget`でポップオーバーを開くと、ポップオーバーの操作要素はそのボタンの直後に来ます。「予約する」からTabを押すと最初の日付へ、「次へ」の後のTabは「地図で開く」へ移り、スクリプトに残した1つのリスナーが、リンクを覆わないようシートを閉じます。スクリプトが行っていたほかのことは、ブラウザーが行います。Escapeキーでシートを閉じてフォーカスを「予約する」に戻し、「予約する」が展開されているか折りたたまれているかも伝えるため、合わせて更新する`aria-expanded`は要りません。シートはページのほかのすべての上、最上位レイヤーに描かれるため、親要素に切り取られることも、ほかの内容がその上に描かれることもありません。シートの外をクリックしても閉じます。スクリーンリーダーのブラウズモードで「予約する」から読み進めると、シートにはマークアップ上の位置、ページの最後で届きます。ブラウザーは`aria-details`と同じように「予約する」とシートを関連付け、それを伝えるスクリーンリーダーもあります。対応するすべてのブラウザーで順序を確認してください。Chrome、Firefox、Safariはどれも`popovertarget`に対応していますが、WebKitは2024年にポップオーバーでのTabの動きを変更しています。

## 修正後：内容と一緒のバーと、シートへ移すフォーカス

```css styles.css
/* バーのための余白。ページの最後やフォーカスを覆わないようにする。 */
html {
  scroll-padding-bottom: 5rem;
}
body {
  padding-bottom: 5rem;
}
.book-bar {
  position: fixed;
  inset-inline: 1rem;
  bottom: 1rem;
  display: flex;
  align-items: center;
  justify-content: space-between;
  /* 高さ4rem、下端から1rem：確保した5remに収まる。 */
  height: 4rem;
  padding: 0 1rem;
  border-radius: 1rem;
  background: #fff;
}
.sheet {
  position: fixed;
  inset-inline: 1rem;
  bottom: 5.5rem;
  padding: 1rem;
  border-radius: 1rem;
  background: #fff;
}
```

```html index.html
<main>
  <h1>旧市街ウォーキングツアー</h1>
  <p>2時間、1人$25から</p>
  <div class="book-bar">
    <p>$25から</p>
    <button type="button" class="book-button" aria-expanded="false" aria-controls="booking">予約する</button>
  </div>
  …
</main>
<footer>…</footer>
<div class="sheet" id="booking" hidden>
  <h2>日付を選ぶ</h2>
  <form action="/checkout">
    <fieldset>
      <legend>日付</legend>
      <label><input type="radio" name="date" value="2026-06-13"> 6月13日（土）</label>
      <label><input type="radio" name="date" value="2026-06-14"> 6月14日（日）</label>
      <label><input type="radio" name="date" value="2026-06-20"> 6月20日（土）</label>
    </fieldset>
    <button type="submit">次へ</button>
  </form>
</div>
```

```js script.js
const button = document.querySelector('.book-button');
const sheet = document.querySelector('#booking');

function setOpen(open) {
  sheet.hidden = !open;
  button.setAttribute('aria-expanded', String(open));
}
button.addEventListener('click', () => {
  setOpen(sheet.hidden);
  // シートはフッターの後にあるため、フォーカスをそこへ移す。
  if (!sheet.hidden) sheet.querySelector('input').focus();
});
sheet.addEventListener('keydown', (event) => {
  if (event.key === 'Escape') {
    setOpen(false);
    button.focus();
  }
});
// ページのほかの部分へ移ると閉じ、フォーカスのある所を覆わない。
sheet.addEventListener('focusout', (event) => {
  const next = event.relatedTarget;
  if (next && next !== button && !sheet.contains(next)) setOpen(false);
});
```

バーは価格の直後に移し、シートはフッターの後に置いたままにします。シートを開くとフォーカスが最初の日付へ移り、スクリーンリーダーは、グループ名の「日付」と合わせて読み上げます。Escapeキーでフォーカスが「予約する」に戻るため、F85のテストの前半も後半も満たします。変わらないのは、シートの前後の順序です。日付からShift + Tabを押すと、シートを閉じながらフッターの最後のリンク「お問い合わせ」へ移り、「次へ」の後でTabを押すと、ページを出てブラウザー自体の操作部分へ移ります。シートを閉じずに外へ出たキーボード利用者は、ページの最後に着き、そこから「予約する」を探し直すことになります。

## どの方法を選ぶか

3つとも「予約する」を価格と一緒に置き、2.4.3を満たします。シートをバーの直後に移す方法は、ほかに何も足さない最小の変更で、スクリーンリーダーで「予約する」から読み進めても次に日付に届くのは、どのブラウザーでもこの方法だけです。ただし、バーとシートの親要素が`position: fixed`や重なり順に影響しないことが条件です。ポップオーバーは、開く、Escapeキーで閉じる、フォーカスを戻すためのスクリプトが要らず、「予約する」が展開されていることをスクリーンリーダーに伝え、マークアップがどこにあってもシートをすべての上に描きます。予約ウィジェット、テーマ、コンポーネントライブラリーがパネルをページの最後に置く場合は、この方法を使います。ブラウズモードでは、シートは引き続きそこで読まれます。シートへフォーカスを移す方法は、外部サービスのスクリプトが追加するシートのように、移動もポップオーバーへの変更もできないシートのためのものです。シートからTabやShift + Tabで出るとページの最後へ移るため、これだけでは不十分です。

## 実装の判断

浮いたボタンは、その内容がある位置に書きます。「予約する」バーは、ツアー名と、それが繰り返す価格の後に、「絞り込み」ボタンは絞り込む商品の前に、「カートに入れる」バーは商品名と価格の後に置きます。画面のどの角に描くかは、キーボードやスクリーンリーダーには何の意味もありません。ページの上のほうにページ自体の「予約する」ボタンがある場合、浮いたバーは同じ操作への2つ目の手段です。ページ自体のボタンに早く届くなら、バーは最後のままでもかまいません。

この例のシートは、後ろのツアーの説明を読めるよう、モーダルではありません。シートがページを覆い、後ろの内容を使えない場合は、モーダルダイアログにします。フォーカスがその中へ移り、閉じるまで中にとどまります。[背後にフォーカスが残るモーダル](/ja/learn/modal-focus-management)を参照してください。

ここでのどの方法も、フォーカスがシートの中から「予約する」以外のページ上の要素へ移ると、シートを閉じます。[Tabで閉じてフォーカスを見失う検索パネル](/ja/learn/panel-dismissal)が、フォーカスが部品全体から出たときに閉じるのと同じです。開いたままにすると、Tabで進んだ先をシートが覆い、フォーカスのある操作要素を完全に隠すことがあります。達成基準2.4.11 フォーカスの非隠蔽（最低限）が、利用者が開いた内容にそれを認めるのは、フォーカスを動かさずに隠れた部分を表示できる場合だけです。リスナーはフォーカスの移り先である`relatedTarget`を読むため、フォーカスがほかの操作要素に移らないシートの余白のクリックや、ページの外へのTabでは閉じません。バー自体は、`scroll-padding-bottom`とページの終わりの余白で5rem分を空けているため、フォーカスもページの最後も覆いません。[拡大するとページを覆う、浮いた購入バー](/ja/learn/floating-buttons)を参照してください。

予約ウィジェットやコンポーネントライブラリーは、親要素に切り取られないよう、バー、ポップオーバー、メニュー、シートを、Reactの`createPortal`やVueの`Teleport`のようなポータルを使って`body`の最後に描くことがよくあります。その場で描くオプションや、HTML標準のポップオーバーを使うオプションを探してください。どちらもない場合はパネルへフォーカスを移し、Escapeキーでフォーカスがボタンに戻ることを確認します。

## 修正の確認

1. ページの最初から、浮いたボタンに届くまでTabを押す。ボタンはフッターより前、その内容と一緒に来る。
2. Enterキーでシートを開く。次のTabでシートの最初の操作要素にフォーカスが移るか、すでにそこにある。
3. Tabでシートの中を進み、最後の操作要素の先へ進む。フォーカスがシートのすべての操作要素を通り、ページ上でボタンの次にある内容へ移る。そのときシートが閉じ、フォーカスのある操作要素を何も覆わない。
4. もう一度シートを開き、最初の操作要素からShift + Tabで戻る。フォーカスがボタンへ移る。
5. シートを開いてEscapeキーを押す。フォーカスがボタンにあり、ボタンが折りたたみと読まれる。
6. スクリーンリーダーでページを最初から読む。ボタンがその内容と一緒に読まれる。シートを開いてTabを押すと、ページとフッターの後ではなく、次に最初の選択肢が読まれる。マークアップ上でシートがボタンの直後にあれば、ブラウズモードで読み進めても次にシートの見出しに届く。ポップオーバーは、引き続きマークアップ上の位置、ページの最後で読まれる。

OS、ブラウザーと支援技術のバージョン、ビルド、実施日、各手順の実際の結果を記録してください。バー、シート、ページのレイアウトを変更した際や、予約ウィジェット、コンポーネントライブラリー、外部サービスのスクリプトを更新した際は、再度確認します。

## 制限

このサンプルは、どのアプリケーションでも同じ結果になることを保証するものではありません。バー、シート、ツアーはこの例のものです。チャット、ヘルプ、フィードバックのパネルも含め、ページ上のすべての浮いたボタンと、それが開くすべてのパネルを、表示される最も長いページで確認してください。浮いたボタンが順序の最後にあってよいかどうかは、ページに対する判断です。「ページ上部へ」ボタンは最後でよく、ページの主な操作はそうではありません。チャットのパネルはメッセージの読み上げも必要です（[メッセージを読み上げないチャットウィジェット](/ja/learn/chat-widgets)）。ポップオーバーのフォーカス順序はブラウザーによって異なるため、対応するブラウザーそれぞれで確認してください。コード内のクラス名は、実際のものに置き換えてください。

---

このガイドをコーディングエージェントで使う: MCP https://easeweb.dev/mcp（設定は https://easeweb.dev/ja/services/developers）
