スクロール スナップ位置を宣言して、制御されたスクロール エクスペリエンスを作成します。
CSS スクロール スナップ機能を使用すると、ウェブ デベロッパーはスクロール スナップ位置を宣言することで、制御されたスクロール エクスペリエンスを作成できます。ページネーション付きの記事や画像カルーセルは、この例としてよく使用されます。CSS スクロール スナップは、これらの一般的な UX パターンを構築するための使いやすく一貫性のある API を提供します。
背景
スクロール スナップを使用する理由
スクロールは、ウェブ上のコンテンツを操作する一般的な方法です。画面に一度に表示できる情報量を超える情報にアクセスするためのプラットフォームのネイティブな手段であり、画面領域が限られているモバイル プラットフォームでは特に重要です。そのため、ウェブ作成者が、深い階層ではなく、スクロール可能なフラットなリストにコンテンツを整理することを好むようになっているのは当然のことです。
スクロールの主な欠点は精度が低いことです。スクロールが段落や文に揃うことはほとんどありません。ページネーションや項目化されたコンテンツで、意味のある境界があり、ページまたは画像の途中でスクロールが終了して一部が可視状態になる場合は、この問題がさらに顕著になります。これらのユースケースでは、スクロールを適切に制御することが重要です。
ウェブ デベロッパーは長い間、この欠点を解消するために、スクロールを制御する JavaScript ベースのソリューションに頼ってきました。ただし、JavaScript ベースのソリューションでは、スクロールのカスタマイズ プリミティブが不足しているため、または合成スクロールにアクセスできないため、完全な忠実度ソリューションを提供できません。CSS スクロール スナップは、ブラウザ間で一貫して動作する、高速で忠実度が高く、使いやすいソリューションです。
CSS スクロール スナップを使用すると、ウェブ作成者は各スクロール コンテナに、スクロール オペレーションを終了する境界をマークできます。ブラウザは、スクロール オペレーションの詳細、スクロール コンテナのレイアウトと可視性、スナップ位置の詳細に応じて、最も適切な終了位置を選択し、スムーズにアニメーション化します。前の例に戻ると、ユーザーがカルーセルのスクロールが完了すると、表示されている画像がスナップして固定されます。JavaScript によるスクロール調整は不要です。
CSS スクロール スナップ
スクロール スナップとは、スクロール オペレーションが完了した後に、スクロール コンテナのスクロール オフセットを調整して、優先されるスナップ位置に配置することです。
スクロール コンテナは、scroll-snap-type
プロパティを使用してスクロール スナップに対応できます。これにより、このスクロール コンテナを子孫によって生成されたスナップ位置にスナップすることをブラウザに指示します。scroll-snap-type
は、スクロールが行われる軸(x
、y
、both
)と、スナップの厳密度(mandatory
、proximity
)を決定します。詳細については後述します。
スナップ位置は、要素に希望する配置を宣言することで生成できます。この位置は、指定された軸に対して指定されたように、最も近い祖先スクロール コンテナと要素が配置されるスクロール オフセットです。各軸で、start
、end
、center
のいずれかの配置を使用できます。
start
の配置とは、スクロール コンテナのスナップポートの開始エッジを要素のスナップ領域の開始エッジとフラッシュすることを意味します。同様に、end
と center
の位置揃えは、スクロール コンテナのスナップポートの端または中央を、要素のスナップ領域の端または中央と揃えることを意味します。
次の例は、これらのコンセプトの使用方法を示しています。
例: 横長のギャラリー
スクロール スナップの一般的なユースケースは、画像カルーセルです。たとえば、スクロールするときに各画像にスナップする横向きの画像カルーセルを作成するには、水平軸に必須の scroll-snap-type
を持つスクロール コンテナを指定します。各画像を scroll-snap-align: center
に設定して、スナップがカルーセル内に画像を中央に配置するようにします。
#gallery {
scroll-snap-type: x mandatory;
overflow-x: scroll;
display: flex;
}
#gallery img {
scroll-snap-align: center;
}
<div id="gallery">
<img src="cat.jpg">
<img src="dog.jpg">
<img src="another_cute_animal.jpg">
</div>
スナップ位置は要素に関連付けられているため、スナップ アルゴリズムは、要素とスクロール コンテナのサイズに基づいて、スナップするタイミングと方法をスマートに判断できます。たとえば、1 つの画像がカルーセルよりも大きい場合を考えてみましょう。単純なスナップ アルゴリズムでは、ユーザーが画像全体を表示するためにパンできない場合があります。ただし、仕様では、実装でこのケースを検出し、ユーザーが画像内で自由にスクロールできるようにし、画像の端でのみスナップするようにする必要があります。
例: ジャーニーに沿った商品ページ
スクロール スナップが役立つ一般的なケースとして、縦方向にスクロールする複数の論理セクションがあるページ(一般的な商品ページなど)があります。scroll-snap-type: y proximity;
は、このようなケースに適しています。ユーザーが特定のセクションの中央までスクロールしても邪魔にならないようにし、十分に近づいてスクロールしたときに、新しいセクションに注意を向けるようにします。
手順は次のとおりです。
article {
scroll-snap-type: y proximity;
/* Reserve space for header plus some extra space for sneak peeking. */
scroll-padding-top: 15vh;
overflow-y: scroll;
}
section {
/* Snap align start. */
scroll-snap-align: start;
}
header {
position: fixed;
height: 10vh;
}
<article>
<header> Header </header>
<section> Section One </section>
<section> Section Two </section>
<section> Section Three </section>
</article>
スクロール パディングとスクロール マージン
商品ページの上部に固定位置のヘッダーがある。また、スクロール コンテナがスナップされたときに上部セクションの一部を表示し、上部のコンテンツに関するデザインのヒントをユーザーに提供することも求められました。
scroll-padding
プロパティは、スクロール コンテナ(スナップポート)の有効な表示領域を調整するために使用できる新しい CSS プロパティです。このプロパティは、スクロール スナップの配置を計算する際に使用されます。このプロパティは、スクロール コンテナのパッディング ボックスに対するインセットを定義します。この例では、上部に 15vh
の追加インセットが追加されています。これにより、スクロール コンテナの上端の下にある 15vh
を、スクロール スナップの垂直方向の開始エッジとして考慮するようにブラウザに指示します。スナップすると、スナップ ターゲット要素の開始エッジがこの新しい位置にフラッシュされ、上部にスペースが残ります。
scroll-margin
プロパティは、スナップ ターゲットの有効なボックスを調整するために使用される外側の量を定義します。これは、スナップ スクロール コンテナで scroll-padding
が機能する方法と同様です。
これらの 2 つのプロパティには「snap
」という単語が含まれていないことに気付いたかもしれません。これは、スクロール スナップだけでなく、関連するすべてのスクロール オペレーションでボックスを実際に変更するため、意図された動作です。たとえば、Chrome では、PageDown や PageUp などのページング スクロール オペレーションのページサイズの計算や、Element.scrollIntoView()
オペレーションのスクロール量の計算で、これらの値が考慮されます。
他のスクロール API との連携
DOM Scrolling API
スクロール スナップは、スクリプトによって開始されたものを含むすべてのスクロール オペレーションの後に発生します。Element.scrollTo
などの API を使用すると、ブラウザはオペレーションの目的のスクロール位置を計算し、適切なスナップ ロジックを適用して最終的なスナップ位置を特定します。したがって、ユーザー スクリプトでスナップ用に手動で計算を行う必要はありません。
スムーズ スクロール
スムーズ スクロールはプログラマティック スクロール オペレーションの動作を制御し、スクロール スナップはその宛先を決定します。スクロールの直交する側面を制御するため、併用して相互に補完できます。
オーバースクロールの動作
Overscroll behavior API は、複数の要素間でスクロールを連結する方法を指定し、スクロール スナップの影響を受けません。
注意事項とベスト プラクティス
ターゲット要素の配置が離れている場合は、強制スナップを使用しないでください。その結果、スナップ位置の間にあるコンテンツにアクセスできなくなる可能性があります。
多くの場合、特徴検出を行うことなく、スクロール スナップ機能を追加できます。必要に応じて、@supports
または CSS.supports
を使用して CSS スクロール スナップのサポートを検出します。非推奨の仕様にも存在する scroll-snap-type
は使用しないでください。
CSS での機能検出
@supports (scroll-snap-align: start) {
article {
scroll-snap-type: y proximity;
scroll-padding-top: 15vh;
overflow-y: scroll;
}
}
JavaScript での機能検出
if (CSS.supports('scroll-snap-align: start')) {
// use css scroll snap
} else {
// use fallback
}
Element.scrollTo
などのプログラムによるスクロール API が、常にリクエストされたスクロール オフセットで終了することを前提としないでください。スクロール スナップは、プログラムによるスクロールが完了した後にスクロール オフセットを調整することがあります。スクロール スナップ前でも、スクロールが他の理由で中断される可能性があるため、これは良い前提ではありませんでした。これは特にスクロール スナップの場合に当てはまります。
今後の作業
スクロール エクスペリエンスは、Chrome チームによる最近の調査の焦点でした。アンケート結果から、プラグイン ライブラリと CSS のギャップを縮小するために追加の作業が必要ないくつかの領域が特定されました。今後の作業では、scroll-snap
に重点を置きます。具体的には、次の作業を行います。
- ブラウザ間での API の可用性と互換性。
scroll-start
などの新しい CSS API の開発に取り組んでいます。snapChanged()
などの新しい JS イベントの開発。