ランディングページやドキュメントの静的HTMLは、2026年も配信コストの観点で有利です。一方でモーダルを開いたあともTabキーでフッターリンクに入ってしまう、VoiceOverが背後の見出しを読み上げる——これは半透明オーバーレイだけでは防げません。inert はサブツリー全体を非対話にし、ポインタ命中とフォーカス移動の両方を止めます。リンクごとに tabindex="-1" を並べるより壊れにくいのが実務的な利点です。
本稿では Popover API のパターン、@layer を使ったカスケード設計、MPA向けView Transitions と横断的に読み替え、Safari WebKit での検証手順とクラウド Mac mini(公開価格で1日あたり約16.9ドル)を使った受け入れ基準をまとめます。
inertの意味とスコープ
HTML仕様上、inert はブール属性で、要素とその子孫をユーザー操作から隔離します。視覚的には残るため「非表示」とは異なります。静的サイトでは #page-shell にヘッダー・本文・フッターを包み、モーダルだけを兄弟として外に出す構成が扱いやすいです。開くとき shell.inert = true、閉じるとき false に戻すだけの状態機械をバニラJSで持てば、フレームワーク無しでも破綻しにくいです。
フォームの disabled が個々のコントロールにしか効かないのに対し、inert は任意のマークアップに適用できます。AstroやEleventyの出力にそのまま載せられるのも魅力です。URLハッシュや history.pushState と組み合わせ、共有リンクでモーダル状態を再現する場合でも、初期HTMLでは非表示にしておき、拡張レイヤーでのみ inert を切り替えると段階的改良がしやすいです。
aria-hiddenやネイティブdialogとの違い
aria-hidden="true" は補助技術ツリーから外す属性であり、クリックやフォーカスを自動では止めません。z-indexの競合で「見えないのに押せる」ケースが残りがちです。inert はヒットテストとフォーカス巡回の両方を抑止するため、モーダル期待に近い挙動になります。ネイティブ dialog.showModal() はトップレイヤーやフォーカストラップを持ちますが、デザイン自由度やブラウザ差の観点から inert を併用するチームも多いです。
第三者の iframe(チャット、地図、広告)には祖先の inert が及ばないことがあります。契約で tabindex や可視性フックを取り決め、同意前はフォーカス可能要素を出さないよう要求してください。仕様書の冒頭に1段落書くだけで、後工程の手戻りを数時間単位で削れます。
Safari・VoiceOver・Retinaの注意点
2026年時点のWebKitは inert を広く実装していますが、VoiceOverは inert 境界と aria-modal を重ねると二重に読み上げることがあります。初回のスクリーンリーダー走査で冗長なロールを削ってください。また backdrop-filter を兄弟要素に置いた場合、2xディスプレイでヒットテストが微妙にズレる報告があります。シミュレータだけでなく実機Retinaで確認が必要です。Safari Technology Previewは安定版より先行するため、STPと安定版の両方に結果を残すとサポートが楽です。
計測の目安として、モーダル直後の主ボタンに対する最初の pointerdown は冷えたキャッシュでも120ミリ秒以内が望ましいです。それを超える場合、透明オーバーレイがイベントを奪っている可能性が高いです。LCPやCLSと同じダッシュボードに並べると非エンジニアにも説明しやすくなります。夜間にWebKitスモークを回すなら、Apple SiliconのMac miniはアイドル時12W前後と静かで、オフィスに置いても負担が少ないのが利点です。
ドロワーや埋め込みとの重ね順
クッキーバー、ヒーロー動画、チャットバブルが同時に存在するページでは、z-indexの設計表を作ってください。例として本文0–99、固定ナビ100–199、モーダル1000以上のように帯域を決め、巨大な整数を禁止します。法的バナーを操作可能にしたいときは本文側に inert をかけ、同意ボタンだけ外に出す、逆パターンもあります。
View Transitionsでページ遷移アニメーションを挟む場合、アニメーションPromiseが解決するまで inert を外さない方が安全です。さもないとフォーカスがフェード途中のノードに残り、VoiceOverが途中経過を読み上げます。prefers-reduced-motion: reduce ではアニメーションを実質1フレームに縮め、フォーカス順序の再現性を優先してください。
計測・リプレイ・回帰防止
セッションリプレイSDKが透明なキャプチャ層を張ると、背景をinertにしてもイベントが抜けないことがあります。計測スクリプトをinert対象のシェル内に置くか、モーダル表示中はリプレイを一時停止してください。E2Eではモーダルオープン中にヒーローCTAへのアクティベーションが0回であることをアサートします。
開発中のみ focusin で document.activeElement をログし、リリースビルドでは除去します。障害対応のため5分だけ再有効化できるフラグを持つと便利です。Safariのバージョン文字列とmacOSのマイナー番号をリリースノートに残し、サポートがチケットを突き合わせやすくしてください。
意思決定マトリクス
| シナリオ | 推奨 | 理由 |
|---|---|---|
| 単一モーダルのLP | inertシェル + dialogロール | JSが小さくヒットテストが明快 |
| 多段ウィザード | ネイティブdialog/popover | トップレイヤーとライトディスミス |
| 第三者iframe | 契約とtab順制御 | inertは越境しない |
| 障害時の全解除 | ホットキーでinertとhiddenを一括解除 | 運用が自己救済できる |
最小バニラ切替
const shell = document.querySelector('#page-shell');
const dlg = document.querySelector('#modal');
function openModal() {
shell.inert = true;
dlg.hidden = false;
dlg.querySelector('button[data-close], [autofocus]')?.focus();
}
function closeModal() {
dlg.hidden = true;
shell.inert = false;
}
リリース前チェックリスト
- モーダル表示中にキーボードで前後方向へ全要素を巡回し、フォーカスが背景へ逃げないことを確認する。
- VoiceOverをオンにして同じ巡回を行い、逸脱回数0を目標にする。
- ビューポート幅320px、768px、1280pxでスクロール連鎖と透過クリックを確認する。
- 主CTAに一時的な
pointerdownカウンタを付け、モーダル中は0であることを見る。 - Safari安定版とChromiumで画面録画を添付し、少なくとも90日保管する。
企業調達では補助技術テストの証跡を求められる場面が増えています。ローカル実機が無いスプリントでは、クラウドMac miniを数日借りる方がリリース延期リスクを下げやすいです。公開価格の1日16.9ドル前後を予算の目安に置くと稟議が通りやすいでしょう。
状態管理表に「inert中も動かすSDK(決済など)」と「必ず停止する埋め込み(自動再生プレビューなど)」を明記し、README先頭に貼っておくとオンボーディングが15分で済みます。日英併記サイトでも切替ロジックは共通化し、文言だけをローカライズすると二重保守を避けられます。
ショートカットキー(Escで閉じる、全オーバーレイを強制解除する組み合わせ)をヘルプに書くと、インシデント時の自己救済が速くなります。クラウドminiにデモ動画を置けば、文章仕様より説得力が増します。
FAQ
inertで背景テキストは読まれなくなる?
自動では消えません。非表示にしたい場合は別の手段が必要です。
アニメーションの各フレームでinertを切替えてよい?
レイアウトスラッシングの原因になるため、開閉イベントに限定してください。
shadow treeは?
inert祖先の下ではshadow内も非対話になります。slot設計に注意してください。
Apple SiliconのMac miniは、WebKitの実挙動を静かな環境で追うのに向いています。MacHTMLのクラウドノードはSSHと任意のVNCを備え、分散メンバーが同じmacOSプロファイルを共有できます。プロジェクト終了後はインスタンスを停止し、36か月償却のハード購入と比べてキャッシュアウトを抑えられます。
モーダルアクセシビリティは一度通したら終わりではなく、マーケの埋め込み差し替えやSafariマイナーアップデートのたびにフォーカス経路が変わります。検証を「借りられるMac mini」の運用に落とし込むと、チームは1日あたり約16.9ドルという予測可能なコストでWebKit品質を維持しやすくなります。
Safariのinert検証をクラウドMac miniで
実機macOS上でinert・dialog・popoverのフォーカス順を確認してから静的HTML変更を本番へマージしましょう。