ピン留めスクロール
あるセクションが画面に固定されたまま、スクロール進行に応じて内部の要素(テキスト/数値)が切り替わる。position:sticky+スクロール進捗で内部をmorph。
プレビュー
スクロール
操作枠内をスクロールすると動きます。
仕様書
- 向く場面
- 固定した画面で数値・文言を段階的に切り替える
- 3ステップの説明をスクロールで進める
- サービス紹介の「ピン留め」区間
- 避ける場面
- ステップが多くスクロール量が長すぎる構成
- 内容が長文で1画面に収まらない
- 構成要素
- スクロール容器
- 固定ステージ
- スライド(番号と文)
- ドット
- 持っている状態
- 通常
- キーボード
Tab でスクロール容器へ(tabindex=0)、↑↓/PageDown でスクロール
- 支援技術
3枚のスライドは常に DOM にあり、非表示のスライドは aria-hidden で読み上げから外す。現在位置はドットの色+番号の文字。reduced-motion では切替を即時に
- 動き
スライド切替は fade+20px rise 400ms ease、ドット 300ms。スクロール量を3等分して段階的に切り替える
デザインの要点
- 固定区間の長さはステージ 300px+下の余白 400px。1 スライドあたり約 170px のスクロールで、指 1 回のフリックで次へ進む
- 進捗を floor(progress × 3) で 3 段に量子化する。連続値で fade を混ぜると 2 枚が重なった中間状態が読めない
- スライドは absolute で重ね、ステージの高さを 180px に固定する。切替で高さが変わると下のドットが跳ねる
- 非表示スライドは opacity 0 のまま DOM に残るので aria-hidden を切り替える。見えない 3 枚分が読み上げられるのを防ぐ
コード(コピーして使えます)
<div class="pin-root" tabindex="0">
<div class="pin-spacer-top">↓ スクロール ↓</div>
<div class="pin-track">
<div class="pin-stage">
<div class="pin-slide" data-index="0">
<div class="pin-num">01</div>
<p class="pin-text">アイデアを<br>書き出す</p>
</div>
<div class="pin-slide" data-index="1">
<div class="pin-num">02</div>
<p class="pin-text">優先度を<br>整理する</p>
</div>
<div class="pin-slide" data-index="2">
<div class="pin-num">03</div>
<p class="pin-text">形にして<br>届ける</p>
</div>
</div>
<div class="pin-dots">
<span class="pin-dot active" data-i="0"></span>
<span class="pin-dot" data-i="1"></span>
<span class="pin-dot" data-i="2"></span>
</div>
</div>
<div class="pin-spacer-bot"></div>
</div>