ウォークスルー
初回ガイド(コーチマーク)。暗転した画面で1つのUI要素だけをスポットライトで照らし、吹き出しの「次へ/スキップ」で3ステップ進むたびにハイライトが移動する。ドットで現在地を示す。
プレビュー
クリック
操作クリック/タップで動きます。
仕様書
- 向く場面
- 初回起動で主要な3〜4箇所を順に案内するコーチマーク
- 暗転して1要素だけ照らしたいガイド
- 「?」で何度でも再生できるツアー
- 避ける場面
- 説明が5ステップを超える(離脱する)
- 対象要素が画面外や動的に消える画面
- 構成要素
- 背後のアプリ
- 暗転オーバーレイ
- スポットライト
- 吹き出し(見出し・本文)
- ドット
- スキップ・次へ
- 持っている状態
- 通常
- ホバー
- 押下中
- キーボード
開始時は「次へ」にフォーカス。Tab はスキップ/次への間を循環(背後のアプリへ出ない)、Enter/Space で進む。Esc で終了し「?」ボタンへフォーカスが戻る
- 支援技術
吹き出しは role=dialog・aria-modal・aria-labelledby/describedby(本文+「ステップ N / 3」)。表示中は背後のアプリと「?」を inert にし、オーバーレイの aria-hidden を切替。ドットは aria-hidden
- 動き
スポットライトと吹き出しの位置 320ms cubic-bezier(0.4,0,0.2,1)(対象の移動を追える)、暗転 200ms。reduced-motion で無効
デザインの要点
- 穴は対象の矩形に 6px の余白を足して開ける。ぴったりだと枠線が対象と重なり、何が照らされているか読めない
- 吹き出しは対象が上半分なら下、下半分なら上に置く。位置を 320ms で滑らせると、次の対象がどこか目で追える
- 「スキップ」は必ず最初から出す。3ステップでも強制されると離脱するので、逃げ道を隠さない
- 終了後に「?」を残して何度でも再生できるようにする。一度きりのツアーは読み飛ばした人を救えない
実装メモ
プレビューは枠内に収めるため、ツアーのオーバーレイを position:absolute(ステージ基準)で実装しています。実際のページで画面全体に重ねるときは、いちばん外側のオーバーレイを position:fixed; inset:0 に変え、body 直下など高い階層へ置いてください。ハイライトの穴は「巨大な spread の box-shadow で周囲だけを暗くする」定番の手法で、対象要素の位置・サイズは getBoundingClientRect でステージ基準に換算して求めています。見本は 400ms 後に自動で開始しますが、実運用では初回訪問の判定(保存フラグ)で開始してください。
コード(コピーして使えます)
<div class="wt-stage" id="wtStage">
<!-- 背後のダミーアプリ -->
<div class="wt-app">
<header class="wt-head">
<span class="wt-logo">ちい</span>
<button class="wt-search" id="tgSearch">
<svg width="13" height="13" viewBox="0 0 13 13" fill="none" aria-hidden="true">
<circle cx="5.5" cy="5.5" r="4" stroke="currentColor" stroke-width="1.5"/>
<line x1="8.5" y1="8.5" x2="11.5" y2="11.5" stroke="currentColor" stroke-width="1.5" stroke-linecap="round"/>
</svg>
検索
</button>
<button class="wt-add" id="tgAdd" aria-label="新規作成">
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" aria-hidden="true">
<line x1="8" y1="3" x2="8" y2="13" stroke="currentColor" stroke-width="2" stroke-linecap="round"/>
<line x1="3" y1="8" x2="13" y2="8" stroke="currentColor" stroke-width="2" stroke-linecap="round"/>
</svg>
</button>
</header>
<div class="wt-cards">
<div class="wt-card"></div>
<div class="wt-card"></div>
<div class="wt-card"></div>
</div>
<nav class="wt-nav">
<button class="wt-navi" aria-label="ホーム">🏠</button>
<button class="wt-navi" aria-label="通知">🔔</button>
<button class="wt-navi" id="tgSettings" aria-label="設定">⚙️</button>
</nav>
</div>
<button class="wt-help" id="wtHelp" aria-label="ツアーをもう一度">?</button>
<!-- ツアーオーバーレイ -->
<div class="wt-overlay" id="wtOverlay" aria-hidden="true">
<div class="wt-catch"></div>
<div class="wt-spot" id="wtSpot"></div>
<div class="wt-tip" id="wtTip" role="dialog" aria-modal="true" aria-labelledby="wtTitle" aria-describedby="wtBody wtStep">
<p class="wt-title" id="wtTitle"></p>
<p class="wt-body" id="wtBody"></p>
<p class="wt-sr" id="wtStep"></p>
<div class="wt-foot">
<div class="wt-dots" id="wtDots" aria-hidden="true"></div>
<div class="wt-btns">
<button class="wt-skip" id="wtSkip">スキップ</button>
<button class="wt-next" id="wtNext">次へ</button>
</div>
</div>
</div>
</div>
</div>