DEMO
ドラッグ / ホイール / 矢印キーでスワイプできます
CODE
<div class="demo-stage swc-stage">
<div class="swc-rail" tabindex="0" aria-label="スワイプカルーセル(横スクロール可能)">
<article class="swc-slide swc-s1"><span class="swc-num">01</span><span class="swc-name">DISCOVER</span></article>
<article class="swc-slide swc-s2"><span class="swc-num">02</span><span class="swc-name">DESIGN</span></article>
<article class="swc-slide swc-s3"><span class="swc-num">03</span><span class="swc-name">DEVELOP</span></article>
<article class="swc-slide swc-s4"><span class="swc-num">04</span><span class="swc-name">DEPLOY</span></article>
</div>
<p class="swc-note">ドラッグ / ホイール / 矢印キーでスワイプできます</p>
</div>
.swc-stage { display:flex; flex-direction:column; align-items:center; justify-content:center; gap:1.2rem; padding:2rem 0; background:#0B0B10; min-height:280px; }
.swc-rail {
display:flex; gap:1rem; width:100%; padding:.4rem 1.5rem;
overflow-x:auto; overscroll-behavior-x:contain;
scroll-snap-type:x mandatory; scroll-behavior:smooth;
scrollbar-width:none;
}
.swc-rail::-webkit-scrollbar { display:none; }
.swc-rail:focus-visible { outline:2px solid #E91B89; outline-offset:4px; border-radius:14px; }
.swc-slide {
flex:0 0 78%; max-width:280px; height:150px;
scroll-snap-align:center; scroll-snap-stop:always;
display:flex; flex-direction:column; justify-content:flex-end; gap:.3rem;
padding:1.3rem; border-radius:16px; color:#fff;
}
.swc-s1 { background:linear-gradient(150deg,#E91B89,#B0136A); }
.swc-s2 { background:linear-gradient(150deg,#7B37A8,#4E1F6E); }
.swc-s3 { background:linear-gradient(150deg,#5BAADE,#2F6E96); }
.swc-s4 { background:linear-gradient(150deg,#2A2A32,#15151A); border:1px solid rgba(255,255,255,.12); }
.swc-num { font-family:'JetBrains Mono',monospace; font-size:.7rem; opacity:.8; }
.swc-name { font-family:'Oswald',sans-serif; font-size:1.25rem; letter-spacing:.2em; }
.swc-note { font-size:.72rem; color:#6E6E7A; letter-spacing:.05em; }
@media (prefers-reduced-motion: reduce) {
.swc-rail { scroll-behavior:auto; }
}
AI PROMPT
JavaScriptを使わないスワイプカルーセルを作って。横並びのレールに overflow-x: auto と scroll-snap-type: x mandatory を指定し、各スライドに scroll-snap-align: center を指定するだけでスナップが効く。スライドは flex: 0 0 78% のように幅を割合で固定して、次のカードが少し見える状態にすると「まだ続きがある」と伝わる。scroll-snap-stop: always を付けると勢いよくスワイプしても1枚ずつ止まる。仕上げとして、overscroll-behavior-x: contain で親のスクロールへの伝播を防ぎ、scroll-behavior: smooth でアンカー移動を滑らかにし、scrollbar-width: none と ::-webkit-scrollbar { display: none } でスクロールバーを隠す。アクセシビリティ: レールに tabindex="0" と aria-label を付けると、キーボードの矢印キーでスクロールでき、支援技術にもスクロール領域として伝わる。@media (prefers-reduced-motion: reduce) では scroll-behavior: 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 の scroll-snap を使い、JavaScriptなしでスライドが1枚ずつ吸着するカルーセルを作る手法です。慣性スクロール・タッチ追従・キーボード操作といった、自前実装では手間のかかる挙動がすべてブラウザ標準として手に入ります。
当サイトの Crossfade Gallery は時間で自動的に切り替わる表現、Stacked Cards は重なったカードをめくる表現です。本ページは閲覧者が自分のペースで横に送る別テーマで、モバイルでの一覧表示に最も多く採用される形式になります。
自動再生・ドットのページネーション・無限ループは標準機能では実現できません。それらが要件に含まれる場合のみJavaScriptを足す、という判断基準で使い分けてください。
JavaScript製のカルーセルと比べて何が違いますか?
慣性スクロール・タッチの追従・キーボード操作・スクロール位置の復元が、すべてブラウザ標準の挙動として手に入ります。ライブラリの数十KBが不要で、初期表示のブロッキングもありません。一方で「自動再生」「ドットのページネーション」「無限ループ」は標準では実現できないため、それらが必須ならJavaScriptを足すか別実装を選ぶことになります。
スライドが中途半端な位置で止まります。
scroll-snap-align の指定漏れが最も多い原因です。親の scroll-snap-type だけではスナップ位置が定義されないため、子側に center や start を指定する必要があります。また、勢いよくスワイプすると複数枚を飛ばすことがあるので、1枚ずつ止めたい場合は scroll-snap-stop: always を追加してください。
コードは無料で使えますか?
はい。Motion LabのコードスニペットとAIプロンプトは、クレジット表記なしで自由に使えます。コピーしてそのままプロジェクトに利用できます。