アクションシート
画面下からせり上がるiOS風のアクションシート。操作の一覧と、離れた位置の「キャンセル」を持ち、破壊的操作は朱色で示す。背景クリック・Escで閉じる。
プレビュー
クリック
操作クリック/タップで動きます。
仕様書
- 向く場面
- スマホで対象に対する操作を一覧で選ばせる
- 共有・書き出しなど数個の選択肢
- 破壊的操作を離れたキャンセルと並べる
- 避ける場面
- PC 中心の画面(コンテキストメニューで)
- 入力フォームを載せる(モーダルで)
- 項目が 6個を超える一覧
- 構成要素
- 起点ボタン
- 背景(暗幕)
- シート
- タイトル
- 操作項目
- キャンセル
- 持っている状態
- 通常
- ホバー
- フォーカス
- 押下中
- キーボード
開くと先頭項目へフォーカス。Tab/Shift+Tab はシート内で循環、Esc で閉じて起点ボタンへ戻る。項目は Enter/Space。閉じている間は項目に Tab が入らない
- 支援技術
role=dialog aria-modal=true aria-labelledby 付き。閉じている間は inert+visibility:hidden、閉時に起点へフォーカスを戻す。破壊的項目は色+文言。reduce で停止
- 動き
背景 250ms フェード・シートは 300ms cubic-bezier(.32,.72,0,1) で下から上がる。画面下端から出る位置の連続性
デザインの要点
- 「キャンセル」は操作の群から 8px 離した別のカードにする。並べると「削除する」と押し間違える
- 項目は 46px 以上の高さで縦に積む。親指で下から順に届く配置が、このシートをモバイル向けにしている
- シートは translateY(100%) から 300ms で上がる。画面下端から出る動きで「今の画面の上に一時的に乗った」ことを示す
- 閉じている間は inert+visibility:hidden。opacity や transform だけで隠すと、画面外の 5 つのボタンに Tab が入る
実装メモ
プレビューは枠内に収めるため、シートと背景を position:absolute(ステージ基準)で実装しています。実際のページで画面下端に固定するときは position:fixed; left:0; right:0; bottom:0 に変え、body 直下など高い階層へ置いてください。iOS 実機では下端のセーフエリアを避けるため env(safe-area-inset-bottom) 分の padding を足すと自然です。
コード(コピーして使えます)
<div class="stage" id="stage">
<button class="open-btn" id="openSheet">共有・操作</button>
<div class="backdrop" id="backdrop" aria-hidden="true"></div>
<div class="sheet-wrap" id="sheetWrap" role="dialog" aria-modal="true" aria-labelledby="sheetTitle" aria-hidden="true" inert>
<div class="sheet-group">
<p class="sheet-title" id="sheetTitle">操作を選択</p>
<button class="sheet-item" id="firstItem">
<svg width="17" height="17" viewBox="0 0 17 17" fill="none" aria-hidden="true">
<path d="M6 9.5l5-5M11 4.5h-3M11 4.5v3M4 7v5.5A1.5 1.5 0 005.5 14h6A1.5 1.5 0 0013 12.5V9" stroke="currentColor" stroke-width="1.4" stroke-linecap="round" stroke-linejoin="round"/>
</svg>
リンクをコピー
</button>
<button class="sheet-item">
<svg width="17" height="17" viewBox="0 0 17 17" fill="none" aria-hidden="true">
<rect x="2.5" y="4" width="12" height="9" rx="1.5" stroke="currentColor" stroke-width="1.4"/>
<path d="M3 5l5.5 4L14 5" stroke="currentColor" stroke-width="1.4" stroke-linecap="round" stroke-linejoin="round"/>
</svg>
メールで送る
</button>
<button class="sheet-item">
<svg width="17" height="17" viewBox="0 0 17 17" fill="none" aria-hidden="true">
<path d="M8.5 2.5c3.3 0 6 2.1 6 4.8s-2.7 4.8-6 4.8c-.7 0-1.4-.1-2-.3L3 13l.8-2.4C3 9.8 2.5 8.6 2.5 7.3c0-2.6 2.7-4.8 6-4.8z" stroke="currentColor" stroke-width="1.4" stroke-linejoin="round"/>
</svg>
メッセージで共有
</button>
<button class="sheet-item sheet-item--danger">
<svg width="17" height="17" viewBox="0 0 17 17" fill="none" aria-hidden="true">
<path d="M3 4.5h11M6 4.5v-1a.6.6 0 01.6-.6h3.8a.6.6 0 01.6.6v1M5.5 4.5l.5 9M11 4.5l-.5 9M4 4.5l.6 9.3a.6.6 0 00.6.7h6.6a.6.6 0 00.6-.7L13 4.5" stroke="currentColor" stroke-width="1.4" stroke-linecap="round" stroke-linejoin="round"/>
</svg>
削除する
</button>
</div>
<button class="sheet-cancel" id="cancelSheet">キャンセル</button>
</div>
</div>