DEMO
下へスクロールしてみてください
セクションの先頭で止まります
止まる位置は scroll-snap-align
JavaScript は使っていません
CODE
<div class="demo-stage sss-stage">
<div class="sss-scroller" tabindex="0" aria-label="スクロールスナップのデモ(スクロールしてください)">
<section class="sss-sec sss-a"><span class="sss-no">01</span><h3>Scroll</h3><p>下へスクロールしてみてください</p></section>
<section class="sss-sec sss-b"><span class="sss-no">02</span><h3>Snap</h3><p>セクションの先頭で止まります</p></section>
<section class="sss-sec sss-c"><span class="sss-no">03</span><h3>Align</h3><p>止まる位置は scroll-snap-align</p></section>
<section class="sss-sec sss-d"><span class="sss-no">04</span><h3>Done</h3><p>JavaScript は使っていません</p></section>
</div>
</div>
.sss-stage { display:flex; align-items:center; justify-content:center; padding:1.5rem; background:#0B0B10; min-height:300px; }
.sss-scroller {
width:100%; max-width:420px; height:260px; overflow-y:auto; border-radius:14px;
scroll-snap-type:y mandatory; scroll-behavior:smooth;
border:1px solid rgba(255,255,255,.1);
}
.sss-scroller:focus-visible { outline:2px solid #E91B89; outline-offset:3px; }
.sss-sec {
height:100%; scroll-snap-align:start; scroll-snap-stop:always;
display:flex; flex-direction:column; align-items:center; justify-content:center; gap:.4rem; color:#fff;
}
.sss-sec h3 { margin:0; font-family:'Oswald',sans-serif; font-size:2rem; letter-spacing:.12em; }
.sss-sec p { margin:0; font-size:.85rem; color:rgba(255,255,255,.75); }
.sss-no { font-family:'JetBrains Mono',monospace; font-size:.75rem; color:rgba(255,255,255,.6); }
.sss-a { background:linear-gradient(135deg,#E91B89,#7B37A8); }
.sss-b { background:linear-gradient(135deg,#7B37A8,#5BAADE); }
.sss-c { background:linear-gradient(135deg,#1F2937,#374151); }
.sss-d { background:linear-gradient(135deg,#0F766E,#115E59); }
@media (prefers-reduced-motion: reduce) {
.sss-scroller { scroll-behavior:auto; }
}
AI PROMPT
スクロールするとセクションの先頭でぴたりと止まる縦スクロールをCSSだけで作って。スクロールする親要素に overflow-y:auto と scroll-snap-type: y mandatory を指定し、各セクションに height:100% と scroll-snap-align: start を付ける。勢いよくスワイプしても1枚ずつ止まるように scroll-snap-stop: always を加える。ページの一部に埋め込む場合は overscroll-behavior を指定せず、最後のセクションまで来たら親ページのスクロールへ引き継がせる(contain を付けると端で止まり、閉じ込められたように感じる)。ページ全体を対象にする場合は html 要素に scroll-snap-type を指定する。スクロール領域にキーボードで入れるよう tabindex="0" と aria-label を付け、:focus-visible のアウトラインを出す。scroll-behavior: smooth は @media (prefers-reduced-motion: reduce) で auto に戻すこと。 Acceptance criteria: works with prefers-reduced-motion (animation disabled), zero console errors, zero layout shift
AIエージェントでの実装ガイド → Claude Code でWebアニメーションを実装する
BOOKS · PR · AMAZON
※当サイトはAmazonアソシエイトプログラムの参加者です。リンクから商品をご購入いただくと、当方に紹介料が発生します。
学びを止めない · AMAZONサブスク
※当サイトはAmazonアソシエイトプログラムの参加者です。リンクから商品をご購入いただくと、当方に紹介料が発生します。
スクロールが止まる位置を要素の境目に合わせるCSSの機能です。以前はJavaScriptのライブラリで実装していた全画面スクロールやカルーセルの「1枚ずつ止まる」動きが、scroll-snap-type と scroll-snap-align の2つの指定だけで作れます。
当サイトの Swipe Carousel は横方向に1枚ずつ送るカルーセル、Sticky Sections はスクロールに合わせて前のセクションの上に次が重なる演出です。本ページは縦方向のセクション送りそのものを扱う別テーマで、LPのヒーローや製品紹介の章立てに向きます。
スナップはスクロールの自由を奪う機能でもあります。中身が長いセクションでは読めなくなる、スクロールの途中で止めたい人が止められない、といった不便が起きるため、mandatory と proximity の使い分けと、スクロール領域の高さの設計を先に決めてください。
mandatory と proximity の違いは何ですか?
mandatory はスクロールが止まるとき必ずどこかのスナップ位置へ吸着します。proximity はスナップ位置の近くで止まった時だけ吸着し、離れていればその場に止まります。全画面のセクション送りには mandatory、長い本文の途中に見出しがある記事ページには proximity が向きます。
セクションの中身が画面より長いとどうなりますか?
mandatory の場合、セクションの途中を読もうとしても先頭か次の先頭へ吸着してしまい、長い中身が読めなくなることがあります。中身の高さが変わるページでは proximity に切り替えるか、セクションの高さを min-height ではなく固定値にして中身をその中でスクロールさせてください。
コードは無料で使えますか?
はい。Motion LabのコードスニペットとAIプロンプトは、クレジット表記なしで自由に使えます。コピーしてそのままプロジェクトに利用できます。