1. はじめに
このセクションは規定ではありません。
スクロール可能なコンテンツの一般的なUXパラダイムでは、コンテンツをページごとに切り替えたり、論理的な区分に分割したりすることがよくあります。 特にタッチ操作の場合、階層構造をタップでナビゲートするよりも、平坦に配置されたコンテンツを素早くパン操作する方が、ユーザーにとって速く簡単です。 例えば、ユーザーがアルバム内の多くの写真を閲覧する際、アルバム内の各写真を個別にタップするよりも、写真スライドショーでパン操作する方が簡単です。
しかし、タッチパンやマウスホイールスクロールのようなスクロール入力は精度が低いため、 ウェブ開発者がスクロール体験を十分に制御することは困難です。特にコンテンツをページごとに切り替える効果を作る場合です。 例えば、パン操作によりアイテムが画面に中途半端に表示されてしまうスクロール位置に着地しやすいです。
このため、本モジュールはスクロールスナップ位置を導入し、 スクロール操作完了後にスクロールコンテナのスクロールポートが終了できるスクロール位置を強制します。
また、スナップがオフの場合でもページングやスクロール位置をより細かく制御できるよう、 本モジュールはすべてのスクロールコンテナで使用できるscroll-paddingプロパティを定義し、 ページングやスクロールインビュー操作のためにスクロールコンテナの最適表示領域を調整します。 同様にscroll-marginプロパティは任意のボックスで使用でき、 スクロールインビュー操作のためにその可視領域を調整できます。
1.1. モジュール間の相互作用
このモジュールは[CSS2]の11.1節で定義されているスクロールユーザーインターフェイス機能を拡張します。
このモジュールのいずれのプロパティも、::first-lineおよび::first-letter疑似要素には適用されません。
1.2. 値の定義
この仕様はCSSプロパティ定義の慣例に従い、[CSS2]および値定義構文([CSS-VALUES-3])を使用します。 この仕様で定義されていない値型はCSS Values & Units [CSS-VALUES-3]で定義されています。 他のCSSモジュールと組み合わせることで、これらの値型の定義が拡張される場合があります。
各プロパティの定義に記載されている値に加え、 この仕様で定義されるすべてのプロパティは CSS全体のキーワードもプロパティ値として受け付けます。 読みやすさのため、ここでは明示的に繰り返していません。
2. 動機付け例
img{ /* 各写真の中央が、 スクロールコンテナの中央(X軸)に スナップ時に揃うよう指定 */ scroll-snap-align: none center; } .photoGallery{ width : 500 px ; overflow-x : auto; overflow-y : hidden; white-space : nowrap; /* スクロール操作が完了すると 必ずスナップ位置で止まるよう要求 */ scroll-snap-type: x mandatory; }
< div class = "photoGallery" > < img src = "img1.jpg" > < img src = "img2.jpg" > < img src = "img3.jpg" > < img src = "img4.jpg" > < img src = "img5.jpg" > </ div >

.page{ /* 各ページの上端を スナップ位置として使用するよう定義 */ scroll-snap-align: start none; } .docScroller{ width : 500 px ; overflow-x : hidden; overflow-y : auto; /* 各要素のスナップ領域が、上端から100pxオフセットで揃うよう指定 */ scroll-padding:100 px 0 0 ; /* スクロール操作が完了時、スナップ位置付近ならその位置で止まるよう促す */ scroll-snap-type: y proximity; }
< div class = "docScroller" > < div class = "page" > ページ 1</ div > < div class = "page" > ページ 2</ div > < div class = "page" > ページ 3</ div > < div class = "page" > ページ 4</ div > </ div >

3. スクロールスナップモデル
このモジュールはスクロールスナップ位置の制御を定義します。
スクロールスナップ位置とは、スクロールコンテナ内で特定の揃え方になるスクロール位置のことです。
該当するscroll-snap-typeプロパティをスクロールコンテナに設定することで、
著者はスクロール操作(scrollTo()
メソッド等のプログラム的スクロール含む)後にスクロールポートがどのスナップ位置に着地するかのバイアスを要求できます。
スナップ位置は、 要素のscroll-snap-alignによる特定の整列として指定されます。 スクロールスナップ領域(scroll-marginで修正されたボーダーボックス)の スクロールコンテナのスナップポート(scroll-paddingで縮小されたスクロールポート)内での整列です。 これは概念的には、整列対象を整列コンテナ内で整列することと同等です。 指定された整列を満たすスクロール位置がスナップ位置です。
スクロールポートのスクロール位置をスナップ位置に揃える操作はスナップと呼ばれ、 スクロールコンテナがそのスクロールポートのスクロール位置でスナップ位置になり、 スクロール操作がアクティブでない場合、そのスクロールコンテナはスナップ済みとされます。 CSS Scroll Snap Moduleはスナップ位置を維持するための具体的なアニメーションや物理挙動は定義せず、 それはユーザーエージェントに委ねています。
スナップ位置は、 要素の最近傍のスクロールコンテナ (コンテイニングブロックチェーン上)にのみ影響します。
4. スクロールスナップ領域のキャプチャ: スクロールコンテナのプロパティ
4.1. スクロールスナップ規則: scroll-snap-type プロパティ
名前: | scroll-snap-type |
---|---|
値: | none | [ x | y | block | inline | both ] [ mandatory | proximity ]? |
初期値: | none |
適用対象: | すべての要素 |
継承: | no |
パーセンテージ: | n/a |
算出値: | 指定キーワード |
正規化順序: | 文法による |
アニメーションタイプ: | 離散的 |
scroll-snap-typeプロパティは、 スクロールコンテナがスクロールスナップコンテナかどうか、 どれほど厳格にスナップするか、 そしてどの軸が対象かを指定します。 厳格度が指定されていない場合、proximity がデフォルトとなります。
html { scroll-snap-type: block; /* ドキュメントのメインスクローラーに適用 */ } h1, h2, h3, h4, h5, h6 { scroll-snap-align: start; /* ビューポートの開始位置(上端)にスナップ */ }
UAは、ルート要素に設定されたscroll-snap-type値をドキュメントのビューポートに適用しなければなりません。
overflowとは異なり、scroll-snap-type値は
HTML
body
から伝播されませんので注意してください。
4.1.1. スクロールスナップ軸: x, y, block, inline, both の値
軸値は、スナップ位置がどの軸に影響するか、 またスナップ位置が各軸ごとに独立して評価されるか、 2次元ポイントとして評価されるかを指定します。 各値の定義は以下の通りです:
- x
- スクロールコンテナは水平方向の軸のみでスナップしてスナップ位置を使用します。
- y
- スクロールコンテナは垂直方向の軸のみでスナップしてスナップ位置を使用します。
- block
- スクロールコンテナはブロック軸のみでスナップしてスナップ位置を使用します。
- inline
- スクロールコンテナはインライン軸のみでスナップしてスナップ位置を使用します。
- both
- スクロールコンテナは両方の軸で独立してスナップし、各軸で異なる要素にスナップする可能性があります。
4.1.2. スクロールスナップ厳格度: none, proximity, mandatory の値
厳格度値(none, proximity, mandatory) は、スナップ位置がスクロールコンテナでどれほど厳格に適用されるか(スクロール位置の調整を強制するか)を指定します。 各値の定義は以下の通りです:
- none
- スクロールコンテナに指定した場合、 スクロールコンテナはスナップしません。
- mandatory
- スクロールコンテナに指定した場合、 スクロールコンテナはスクロール操作がアクティブでない時に必ずスナップ位置に揃えられます。 有効なスナップ位置が存在する場合、 スクロール終了時に必ずその位置にスナップします (存在しない場合はスナップしません)。
- proximity
- スクロールコンテナに指定した場合、 スクロールコンテナはスクロール終了時、 UAの判断によりパラメータに応じてスナップ位置に揃える場合があります。
著者は、画面サイズや(該当する場合)コンテンツサイズが様々であることを考慮してmandatoryスナップ位置を使用してください。 特に、スナップされた要素がスクロールポートより大きい場合はUAが対処しますが、 mandatoryスナップを隣接していない兄弟要素に指定すると、 その間のコンテンツがスクリーンより長い場合にアクセスできなくなることがあります。
ボックスは、スナップ位置をキャプチャするためには、 スクロールコンテナであるまたは none以外のscroll-snap-type値を持つ必要があります。 ボックスのスナップ位置キャプチャとして最も近い祖先が、 コンテイニングブロックチェーン上でnon-noneな値を持つ スクロールコンテナであれば、 それがそのボックスのスクロールスナップコンテナです。 それ以外の場合、そのボックスにはスクロールスナップコンテナはなく、 そのスナップ位置はスナップを発生させません。
4.1.3. レイアウト変更後の再スナップ
ドキュメントの内容やレイアウトが変更され (例: 内容の追加、移動、削除、サイズ変更など)、 スナップポートの内容が変わった場合、 UAは結果として生じるスクロール位置を再評価し、 必要に応じて再スナップしなければなりません。 スクロールコンテナが内容変更前にスナップ済みで、そのスナップ位置がまだ存在する場合 (関連する要素が削除されていない等)、 内容変更後もスクロールコンテナは同じスナップ位置に再スナップされなければなりません。 複数のボックスが以前スナップ済みで それらのスナップ位置が一致しなくなった場合、 どれかがフォーカス・ターゲットされていれば スクロールコンテナはそのボックスに再スナップし、 それ以外はUA定義となります。 (UAは例えば、どの要素がスナップされているかを追跡し、レイアウトシフトで他要素のスナップ位置が揃わなくなった時に対応できます。)
新しい/異なるボックスへの再スナップ操作によるスクロールは、 他のスクロールインビュー操作と同様に動作・アニメーションしなければならず、 scroll-behaviorなどのコントロールも尊重されます。 以前と同じボックスへの再スナップ時のスクロール動作はUA定義です。 UAは例えば、 セクション先頭にスナップ済みの場合、 ドキュメント前方に動的に内容が追加されても スクロールのアニメーションを行わず、 スクロールしていないように見せることもできます。
.log{ scroll-snap-type : proximity; align-content : end; } .log::after{ display : block; content : "" ; scroll-snap-align : end; }
これらのルールはスクロールスナップ領域を一つ作成します。これは::after疑似要素で表され、 スクロールスナップコンテナの一番下に配置されます。 ユーザーが下部「付近」にスクロールすると、コンテナはそこにスナップします。 コンテナにさらに内容が動的に追加されても、スナップしたままになります (スクロールコンテナは変更後も同じスクロールスナップ領域が存在すれば再スナップしなければならないため)。 ただし、ユーザーがログ内の別の場所にスクロールしている場合は何も起こりません。
4.2. スクロールスナップポート: scroll-padding プロパティ
名前: | scroll-padding |
---|---|
値: | [ auto | <length-percentage> ]{1,4} |
初期値: | auto |
適用対象: | スクロールコンテナ |
継承: | no |
パーセンテージ: | スクロールコンテナのスクロールポートの対応する寸法に対して相対 |
算出値: | 各辺ごとに、キーワード auto または 算出された <length-percentage> 値 |
アニメーションタイプ: | 算出値型による |
正規順序: | 文法による |
このプロパティは、すべてのスクロールコンテナ(スクロールスナップコンテナだけでなく) に対して、スクロールポートの最適表示領域を定義するオフセットを指定します。 この領域はユーザーが閲覧するために要素を配置するターゲット領域として使われます。 著者は、他のコンテンツ(固定配置のツールバーやサイドバーなど)で隠されているスクロールポートの領域を除外したり、 ターゲット要素とスクロールポートの端との間に余裕を持たせたりすることができます。
scroll-paddingプロパティはショートハンドプロパティであり、 scroll-padding-* ロングハンドを一括で設定します。 各側のロングハンドへの値の割り当ては、padding プロパティと同様です。 各値の意味は以下の通りです:
- <length-percentage>
-
対応するスクロールポートの辺から内側へのオフセットを定義します。 ルートビューポートに適用した場合、オフセットはレイアウトビューポート(ビジュアルビューポートではなく)を基準に計算・適用され、 insetプロパティと同様に 固定配置ボックスに作用します。 最適表示領域はビジュアルビューポートと交差する残りの領域です。
- auto
-
対応するスクロールポートの辺のオフセットはUAによって決定されます。 通常は使用値が0pxとなりますが、UAは非ゼロ値が適切と判断する場合はヒューリスティックを使うことがあります。
これらのオフセットは、スクロールポートの 「表示可能」領域(スクロール操作において)を減少させます。 レイアウトやスクロールの原点・初期位置、実際に要素が可視かどうかには影響しませんが、 要素やキャレットがスクロールインビューであるかどうか(ターゲットやフォーカス操作など)に影響し、 ページング操作(PgUpやPgDnキー、スクロールバーによる同等操作など)のスクロール量も減少させます。 最適表示領域内でユーザーがスクロールポートのスクロールポート上で連続したコンテンツを閲覧できるようにします。
スクロールスナップコンテナの場合、 この領域はスクロールスナップポートも定義します。 これは整列コンテナとして、スクロールスナップ領域の スナップ位置計算時に使われます。
html{ overflow-x : auto; overflow-y : hidden; scroll-snap-type : x mandatory; scroll-padding : 0 500 px 0 0 ; } .toolbar{ position : fixed; height : 100 % ; width : 500 px ; right : 0 ; } img{ scroll-snap-align : none center; }
UAは、ルート要素に設定されたscroll-padding値を
ドキュメントのビューポートに適用しなければなりません。
(ただし、overflowとは異なり、scroll-padding値は
HTML
body
から伝播されません。)
5. スクロールスナップ領域の整列: 要素のプロパティ
5.1. スクロールスナップ領域: scroll-margin プロパティ
名前: | scroll-margin |
---|---|
値: | <length>{1,4} |
初期値: | 0 |
適用対象: | すべての要素 |
継承: | no |
パーセンテージ: | n/a |
算出値: | 各辺ごとに絶対長さ |
正規順序: | 文法による |
アニメーションタイプ: | 算出値型による |
このプロパティはショートハンドプロパティであり、 scroll-margin-* ロングハンドを一括で設定します。 各側のロングハンドへの値の割り当ては、marginプロパティと同様です。
値は、このボックスがスナップポートにスナップされる際に使われる スクロールスナップ領域を定義する外向きのオフセットです。 スクロールスナップ領域は 変形されたボーダーボックスを取得し、 その矩形の境界ボックス(スクロールコンテナの座標空間で軸揃え)を見つけ、 指定された外向きオフセットを加えて決定します。
注: この仕組みによりスクロールスナップ領域は常に矩形となり、 スクロールコンテナの座標空間に軸揃えされます。
ページがフラグメントにナビゲートされ、ターゲット要素が定義されている場合
(:targetで一致する要素や、
scrollIntoView()
のターゲットなど)、
UAは要素のスクロールスナップ領域を利用して
スクロール可能なオーバーフロー領域のどの部分を表示するか決定すべきです。(スナップがオフやこの要素に適用されていない場合でも)
5.2. スクロールスナップの整列: scroll-snap-align プロパティ
名前: | scroll-snap-align |
---|---|
値: | [ none | start | end | center ]{1,2} |
初期値: | none |
適用対象: | すべての要素 |
継承: | no |
パーセンテージ: | n/a |
算出値: | 2つのキーワード |
正規順序: | 文法による |
アニメーションタイプ: | 離散的 |
scroll-snap-alignプロパティは、 ボックスのスナップ位置を スナップ領域(整列対象として)を スナップコンテナの スナップポート(整列コンテナとして)内での整列として指定します。 2つの値は、ブロック軸とインライン軸でのスナップ整列を指定し、 スナップコンテナの書字モードによって決定されます。 1つの値だけ指定した場合、2つ目の値は同じ値がデフォルトになります。
値の定義は以下の通りです:
- none
- このボックスは指定した軸にスナップ位置を定義しません。
- start
- このボックスのスクロールスナップ領域をスクロールコンテナのスナップポートの開始位置に整列することが、指定した軸でのスナップ位置となります。
- end
- このボックスのスクロールスナップ領域をスクロールコンテナのスナップポートの終了位置に整列することが、指定した軸でのスナップ位置となります。
- center
- このボックスのスクロールスナップ領域をスクロールコンテナのスナップポートの中央に整列することが、指定した軸でのスナップ位置となります。
開始・終了の整列は、スナップコンテナのスクロールスナップ領域が スナップポートより大きい場合を除き、 書字モードを基準に解決されます。 (これにより、一般的にはコンテナ内のアイテムのスナップ整列が一貫しますが、 startが常にアイテムを先頭に揃え、 内容の先頭から読めるようにします。)
5.2.1. 有効なスナップ位置の範囲を可視ボックスに限定する
スクロールスナップの目的はスクロールポート内でコンテンツを最適に表示するために整列させることなので、 寄与するスナップ領域が完全にスナップポートの外側になる場合、 たとえスナップ位置が必要な整列条件を満たしていたとしても、 そのスクロール位置は有効なスナップ位置とはみなされません。
╔════viewport════╗┈┈┈┈┈┈┈┈┌──────────────┐ ║ ┌─────┐ ┌──┐ ║ │ top-snapping │ ║ ├──┐ │ └──┘ ║ │ element │ ║ └──┴──┘ ║ │ │ ╚════════════════╝ │ │ └──────────────┘
なぜ要素が可視の時だけスナップを限定するのか?
WebKitの実装者の指摘のように、 スナップエッジをキャンバス全体に無限に拡張すると 格子状レイアウトでのみスナップが可能となり、 画面外要素が画面内要素と揃わない場合、ユーザーには奇妙な挙動になります。 (もしこの要件が実装者にとって負担なら、デフォルトは格子状の挙動にして後からスマートな挙動への切り替えスイッチを導入する案もあります。)注: scroll-snap-type: bothでは スナップ位置を各軸で独立して評価しますが、 一方の軸でのスナップ位置の選択がもう一方の軸のスナップ位置に影響することがあります。 例えば、片方の軸でのスナップがもう一方の軸で揃えるはずのスナップ領域を画面外に押し出すと、 そのスナップ位置は無効となり選択できなくなります。
5.2.2. スクロールポートをはみ出すボックスのスナップ
スナップ領域が 特定の軸でスナップポートより大きい場合、 その軸でスナップ領域がスナップポートを覆い、 またその軸で前後のスナップ位置間の距離が スナップポートのサイズより大きい任意のスクロール位置は、 その軸で有効なスナップ位置となります。 UAは特定のスクロール操作(明示的なページ送りなど)で指定された整列をより精密なターゲットとして利用できます。
スナップ領域が スナップポートより大きい間は、 領域がビューポート全体を埋め尽くしているため、コンテナは任意にスクロールでき、 整列位置に戻ろうとしません。 しかし、コンテナがスクロールされて領域がその軸で完全にビューポートを占めなくなると、 領域は外向きのスクロールに抵抗し、 十分なスクロールで別のスナップ位置にスナップするまで抵抗します。
section
要素で必須の上端スナップを設定すると、
(大きなトップレベルセクションから)大きなスナップ領域が生じ、
その中に(サブセクションから)小さなスナップ領域が含まれる可能性があります。
サブセクションが十分に小さい場合は通常通りスナップしますが、
長い場合はその中や、サブセクションのない大きなセグメント内で自由にスクロールできます。
┌─ top-level section ─┐ ━┓ │ │ 1┃ │ │ ┃ │ │ ━┩ │ │ ┆ │ │ ┆ │┌─── sub-section ───┐│ ╯ ━┓ │└───────────────────┘│ 2┃ │┌─── sub-section ───┐│ ━┓ ┃ ││ ││ 3┃ ━┛ │└───────────────────┘│ ┃ │┌─── sub-section ───┐│ ━┛ ━┓ │└───────────────────┘│ 4┃ │┌─── sub-section ───┐│ ━┓ ┃ ││ ││ 5┃ ━┛ ││ ││ ┃ ││ ││ ━┩ ││ ││ ┆ ││ ││ ┆ ││ ││ ┆ │└───────────────────┘│ ┆ └─────────────────────┘ ╯
注: 著者がセクション自体ではなく各セクションの見出しに必須スナップ位置を設定していた場合、 最初と5番目のセクションの内容はユーザーに部分的にアクセスできなくなります。 これは見出しのスナップ領域がセクション全体を覆わないためです。 そのため、間隔が広くなる可能性のある要素に必須スナップ位置を使うのはおすすめできません。
5.2.3. 到達不能なスナップ位置
スナップ位置が指定通りには到達不能であり、 その位置に整列するにはスクロールコンテナのビューポートを スクロール可能オーバーフロー領域の端を超えてスクロールする必要がある場合は、 このスナップ領域の使用されるスナップ位置は、 各該当軸で希望するスナップ位置に向けて可能な限りスクロールした結果の位置になります。
5.3. スクロールスナップ制限: scroll-snap-stop プロパティ
名前: | scroll-snap-stop |
---|---|
値: | normal | always |
初期値: | normal |
適用対象: | すべての要素 |
継承: | no |
パーセンテージ: | n/a |
算出値: | 指定キーワード |
正規順序: | 文法による |
アニメーションタイプ: | 離散的 |
意図した方向でスクロールした場合、 スクロールコンテナは到達可能な複数のスナップ位置を (同じ方向でより短い距離のスクロール操作ならスナップ可能なものも含めて) スクロール操作の自然な終点に到達し最終的なスクロール位置を選択するまで通過することがあります。 scroll-snap-stopプロパティは、 こうした可能なスナップ位置でスクロール操作を「捕捉」し、 スクロールコンテナが本来の終点に到達する前に停止するよう強制することができます。
値の定義は以下の通りです:
- normal
- スクロールコンテナは、スクロール操作の実行中にこの要素で定義されたスナップ位置を通過しても構いません。
- always
- スクロールコンテナは、スクロール操作の実行中にこの要素で定義されたスナップ位置を通過してはなりません。 代わりにこの要素の最初のスナップ位置でスナップしなければなりません。
このプロパティは、意図した終端位置のみを持つスクロール操作には効果がありません。 そうした操作では、概念的にいかなるスナップ位置も「通過」しないためです。
6. スナップメカニクス
どのスナップ位置にスナップするかを選択する厳密なモデルアルゴリズムは、意図的にほとんど未定義のままです。 これは、ユーザーエージェントがユーザーの意図やインタラクションの高度なモデルを考慮し、 時間の経過とともに応答方法を調整できるようにするためです。 その結果、ユーザーに最適な体験を提供できます。
このセクションでは、スクロールスナップのメカニクスについて議論する際に役立ついくつかの有用な概念を定義し、 効果的なスクロールスナップ戦略がどのようなものかについてガイドラインを示します。 ユーザーエージェントはこのガイダンスを参考にしつつ、 独自の最適な判断を加えてスナップ挙動を定義することが推奨されます。 また、著者がスクロールスナップを考慮してインターフェース設計する際に 最低限頼れる合理的な挙動を保証するための、少数の動作要件も規定します。
6.1. スクロール方法の種類
ページがスクロールされるとき、 その操作は意図した終了位置や意図した方向のいずれかまたは両方を伴って行われます。 これら2つの組み合わせごとに異なるスクロールカテゴリが定義されており、 それぞれが少し異なる扱いを受けます:
- 意図した終了位置
-
「意図した終了位置」のみを伴うスクロールの一般的な例:
-
慣性なしでパン操作を離す
-
スクロールバーの「つまみ」を明示的に操作する
-
scrollTo()
などのAPIによるプログラム的スクロール -
ドキュメント内のフォーカス可能要素をTabで移動する
-
ページ内アンカーへのナビゲーション
-
Home/Endキーなどの「ホーム」操作
-
- 意図した方向および終了位置
-
「意図した方向および終了位置」の両方を伴うスクロールの一般的な例:
-
慣性付きフリック(勢いを伴う)
-
scrollBy()
などのAPIによるプログラム的スクロール -
PgUp/PgDnキー(またはスクロールバーでの同等操作)によるページ送り
スナップポイントなどの機能による介入前のスクロールの意図した終点は、自然終点と呼ばれます。
-
- 意図した方向
さらに、ページレイアウトは通常垂直または水平に要素を揃えるため、 UAはスクロール方向が十分に縦または横であれば軸ロックを行うことがあります。 軸ロックされたスクロールはその軸だけでスクロールします。 これにより、精度が低い入力機構による非主要軸方向へのドリフトを防ぎます。
注: この仕様はUAがサポートするスクロール方法だけに適用されます。 UAに特定の入力やスクロール方法のサポートを義務付けるものではありません。
6.2. スナップ位置の選択
スクロールコンテナには、多くのスナップ領域がスクロール可能オーバーフロー領域内に散在しています。 スナップ位置の選択に単純なアルゴリズムを使うと、ユーザーにとって直感的でない挙動になることがあるので、 選択アルゴリズム設計時には注意が必要です。 以下は選択プロセスの助けとなるポイントです:
-
スナップ位置は、終点(または自然終点)と最終的なスナップスクロール位置との距離を最小化するように選択するべきです。 このセクションで列挙される追加制約も考慮します。
-
スクロールが軸ロックされている場合、 他軸のスナップ位置はスクロール中は無視するべきです。 (ただし、他軸のスナップ位置が最終的なスクロール位置に影響することはあります。)
-
画面外の遠く離れた要素がスクロール位置に分かりにくい影響を与えないように、 スナップ位置は、その要素がスナップポートがスクロール可能オーバーフロー領域内を移動する際に形成される「コリドー」から遠く外れている場合、 または意図した方向のみのスクロールなら仮想「コリドー」から外れた場合、 または意図した終了位置のみのスクロール後のスナップポートから外れている場合は無視するべきです。
-
ユーザーエージェントは、ユーザーがどんなスクロール方法でも「スナップ位置から脱出できる」ことを必ず保証しなければなりません。 例えば、スナップタイプがmandatoryで、 次のスナップ位置が2画面幅以上離れている場合、 単純な「常に最も近い位置にスナップ」アルゴリズムだと、 終点が1画面幅しか離れていない場合にユーザーが「閉じ込められる」可能性があります。 代わりに、終点が元のスナップ位置から十分近い場合だけその位置に戻り、 そうでなければ元のスナップ位置を無視する賢いアルゴリズムの方が望ましいです。
(これは意図した方向のみのスクロールでは、必ず開始スナップ位置を無視すべきことを意味します。)
-
ページがフラグメントにナビゲートされ、ターゲット要素が定義されていて、 その要素がスナップ位置を定義している場合、 UAは最も近いスクロールコンテナがスクロールスナップコンテナであれば その要素のスナップ位置へスナップしなければなりません。 UAは、スクロールコンテナがscroll-snap-type: noneであってもこれを行ってもよいです。
付録A:ロングハンド
物理・論理ロングハンド(およびそれらのショートハンド)は [CSS-LOGICAL-1]で定義される通りに相互作用します。
scroll-paddingの物理ロングハンド
名前: | scroll-padding-top, scroll-padding-right, scroll-padding-bottom, scroll-padding-left |
---|---|
値: | auto | <length-percentage> |
初期値: | auto |
適用対象: | スクロールコンテナ |
継承: | no |
パーセンテージ: | スクロールコンテナのスクロールポートに対して相対 |
算出値: | キーワードautoまたは算出された<length-percentage>値 |
正規順序: | 文法による |
アニメーションタイプ: | 算出値型による |
scroll-paddingのこれらのロングハンドは、scroll-paddingの スナップポートの上・右・下・左の各辺を指定します。 負の値は無効です。
scroll-paddingのフロー相対ロングハンド
名前: | scroll-padding-inline-start, scroll-padding-block-start, scroll-padding-inline-end, scroll-padding-block-end |
---|---|
値: | auto | <length-percentage> |
初期値: | auto |
適用対象: | スクロールコンテナ |
継承: | no |
パーセンテージ: | スクロールコンテナのスクロールポートに対して相対 |
算出値: | キーワードautoまたは算出された<length-percentage>値 |
正規順序: | 文法による |
アニメーションタイプ: | 算出値型による |
scroll-paddingのこれらのロングハンドは、 ブロック始端・インライン始端・ブロック終端・インライン終端の各辺を指定します。 負の値は無効です。
名前: | scroll-padding-block, scroll-padding-inline |
---|---|
値: | [ auto | <length-percentage> ]{1,2} |
初期値: | auto |
適用対象: | スクロールコンテナ |
継承: | no |
パーセンテージ: | スクロールコンテナのスクロールポートに対して相対 |
算出値: | 個々のプロパティを参照 |
アニメーションタイプ: | 算出値による |
正規順序: | 文法による |
ショートハンド(scroll-padding-block-start + scroll-padding-block-endおよびscroll-padding-inline-start + scroll-padding-inline-end)は scroll-paddingのロングハンドであり、 それぞれブロック軸・インライン軸のスナップポートの端を指定します。
2つの値が指定された場合、1つ目が始端の値、2つ目が終端の値になります。
scroll-marginの物理ロングハンド
名前: | scroll-margin-top, scroll-margin-right, scroll-margin-bottom, scroll-margin-left |
---|---|
値: | <length> |
初期値: | 0 |
適用対象: | すべての要素 |
継承: | no |
パーセンテージ: | n/a |
算出値: | 絶対長さ |
正規順序: | 文法による |
アニメーションタイプ: | 算出値型による |
scroll-marginのこれらのロングハンドは、 scroll-marginの スクロールスナップ領域の上・右・下・左の各辺を指定します。
scroll-marginのフロー相対ロングハンド
名前: | scroll-margin-block-start, scroll-margin-inline-start, scroll-margin-block-end, scroll-margin-inline-end |
---|---|
値: | <length> |
初期値: | 0 |
適用対象: | すべての要素 |
継承: | no |
パーセンテージ: | n/a |
算出値: | 絶対長さ |
正規順序: | 文法による |
アニメーションタイプ: | 算出値型による |
scroll-marginのこれらのロングハンドは、 ブロック始端・インライン始端・ブロック終端・インライン終端の各辺を指定します。
名前: | scroll-margin-block, scroll-margin-inline |
---|---|
値: | <length>{1,2} |
初期値: | 0 |
適用対象: | すべての要素 |
継承: | no |
パーセンテージ: | n/a |
算出値: | 個々のプロパティを参照 |
正規順序: | 文法による |
アニメーションタイプ: | 算出値型による |
ショートハンド(scroll-margin-block-start + scroll-margin-block-endおよびscroll-margin-inline-start + scroll-margin-inline-end)は scroll-marginのロングハンドであり、 それぞれブロック軸・インライン軸のスクロールスナップ領域の端を指定します。
2つの値が指定された場合、1つ目が始端の値、2つ目が終端の値になります。
7. プライバシーとセキュリティの考慮事項
この仕様はDOMに既に直接公開されている以外の情報を一切公開しません。 スクロールを少しだけ機能的にするだけです。 新たなプライバシーやセキュリティの考慮事項はありません。
8. 謝辞
David Baron, Simon Fraser, Håkon Wium Lie, Theresa O’Connor, François Remy, Majid Valpour, そして特に Robert O’Callahan に感謝します。 彼らの提案と助言が本書に取り込まれています。
9. 変更点
9.1. 2019年3月19日CR以降の変更点
2019年3月19日候補勧告以降の変更点:
- scroll-snap-alignで どの書字モードが使われるかを明示。 (Issue 3815)
-
複数要素のスナップ位置が一致する場合の再スナップ要件の定義。
(Issue 4651)
スクロールコンテナが内容変更前にスナップ済みで、 そのスナップ位置がまだ存在する場合 (例: 関連要素が削除されていない)、 内容変更後も同じスナップ位置に再スナップしなければならない。 複数ボックスが前回スナップ済みで それらのスナップ位置が一致しなくなった場合、 どれかがフォーカスまたはターゲットされていれば スクロールコンテナはその要素に再スナップし、 それ以外はUA定義となる。 (UAは、どの要素がスナップ済みかを追跡して、 レイアウトシフトで他要素のスナップ位置が一致しなくなった時に対応できる。)
-
新しい要素への再スナップ時は他のscroll-into-view操作同様にアニメーションさせる要件を追加。
(Issue 4609)
新しい/異なるボックスへの再スナップ操作によるスクロールは 他のscroll-into-view操作と同じように動作・アニメーションしなければならない。 scroll-behavior等のコントロールも尊重される。 以前と同じボックスへの再スナップ時のスクロール挙動はUA定義。 UAは例えば、セクション先頭にスナップ済みの場合、 ドキュメント前方に動的に内容が追加されても スクロールをアニメーションせず、 スクロールしていないように見せることもできる。
-
scroll-snap-typeとscroll-padding値が
ルート要素からドキュメントビューポートに伝播することを明示。
(Issue 3740)
UAはルート要素に設定されたscroll-snap-type値を ドキュメントビューポートに適用しなければならない。 overflowとは異なり、 scroll-snap-type値は HTML
body
から伝播しません。UAはルート要素に設定されたscroll-padding値を ドキュメントビューポートに適用しなければならない。 overflowとは異なり、 scroll-padding値は HTML
body
から伝播しません。 -
スナップの整列はビジュアルビューポート基準だが、scroll-paddingはレイアウトビューポート基準で解決されることを明確化。
これにより、ルートビューポートでscroll-paddingとinsetが一貫する。
(Issue 4393)
対応するスクロールポートの辺から内側へのオフセットを定義します。 ルートビューポートに適用した場合、オフセットはレイアウトビューポート(ビジュアルビューポートではなく)基準で計算・適用され、 insetプロパティと同様に 固定配置ボックスに作用します。 最適表示領域はビジュアルビューポートと交差する残りの領域です。
- scroll-padding-inlineとscroll-padding-blockの「適用対象」行を修正。 (Issue 5845)
コメント処理状況が公開されています。
9.2. 2019年1月31日CR以降の変更点
2019年1月31日候補勧告以降の変更点:
-
scroll-paddingとscroll-marginは
スナップがオフでも適用されることを強調。
(Issue 3721)
また、スナップがオフの場合でもページングやスクロール位置の制御をより細かくできるように、 本モジュールはすべてのスクロールコンテナで使用できるscroll-paddingプロパティと、 任意のボックスで使用できるscroll-marginプロパティを定義しています。
このプロパティは (スクロールコンテナすべてが対象で、スクロールスナップコンテナに限りません) スクロールポートの最適表示領域を定義するオフセットを指定します…
ページがフラグメントにナビゲートされ、ターゲット要素が定義されている場合 (:targetで一致する要素や、
scrollIntoView()
のターゲットなど)、 UAは要素のスクロールスナップ領域を利用して スクロール可能なオーバーフロー領域のどの部分を表示するか決定すべきです。(スナップがオフやこの要素に適用されていない場合でも) 。
9.3. 2018年8月14日CR以降の変更点
2018年8月14日候補勧告以降の変更点:
- scroll-paddingのロングハンドに新しいautoキーワードをプロパティ定義テーブルに記載するよう修正。 (Issue 3189)
- プロパティ定義テーブルの「算出値」と「アニメーションタイプ」行を修正。
- <percentage>値がscroll-marginのプロパティ定義テーブルに混入していたのを整理。 (3289)
コメント処理状況が公開されています。
9.4. 2017年12月14日CR以降の変更点
2017年12月14日候補勧告以降の変更点:
- scroll-snap-align のショートハンドで、論理ショートハンド規則に従いブロック軸→インライン軸の順で値を割り当てるよう修正。 (Issue 2232)
- 'scroll-padding'の初期値としてautoキーワードを追加し、UAのヒューリスティックを考慮。 (Issue 2728)
-
scroll-snap-typeの定義に、
scrollTo()
などのプログラム的スクロールもスナップ対象になることを明記。 (Issue 2593)scroll-snap-typeプロパティを該当するスクロールコンテナに設定することで、 著者はスクロール操作完了後にスクロールポートがどのスナップ位置に着地するかのバイアスを要求できる (
scrollTo()
メソッドなどのプログラム的スクロールを含む) 。 - § 5.2.1 有効なスナップ位置の範囲を可視ボックスに限定するの説明をより明確化。 (Issue 2526)
コメント処理状況が公開されています。
9.5. 2017年8月24日CR以降の変更点
2017年8月24日候補勧告以降の変更点:
-
:target/
scrollIntoView()
など はscroll-marginを考慮すべき(スナップの有無にかかわらず)。 (Issue 1)ページがフラグメントにナビゲートされ、ターゲット要素が定義されている場合 (:targetで一致する要素や、
scrollIntoView()
のターゲットなど)、 UAは要素のスクロールスナップ領域を利用して スクロール可能なオーバーフロー領域のどの部分を表示するか決定すべきです。 -
:target/
scrollIntoView()
など は、スナップが有効な場合は必ずスナップ位置を利用しなければならない(should→must)。 (Issue 1)ページがフラグメントにナビゲートされ、ターゲット要素が定義されていて、 その要素がスナップ位置を定義している場合、 UAは
shouldmust その要素のスナップ位置へスナップしなければならない (最も近いスクロールコンテナがスクロールスナップコンテナの場合) 。 UAはスクロールコンテナがscroll-snap-type: noneであっても これを行ってもよいです。 - scroll-snap-marginをscroll-marginに名称変更。 スナップの有無に関わらず要素へのスクロール時に余裕スペースを提供する汎用的役割を反映。 (Issue 4)
コメント処理状況が公開されています。
9.6. 2016年10月20日CR以降の変更点
2016年10月20日候補勧告以降の変更点:
-
scroll-paddingを負の値にできないよう制限。
(Issue 1084)
値は 負であってはならず、 paddingと同様に解釈される …
- ページ送りやホーム操作を§ 6.1 スクロール方法の種類の例に追加。 (Issue 1605)
-
一方の軸でスナップすると、他方の軸で特定のスナップ領域へのスナップが可能かどうかに影響することを明確化。
(Issue 950)
scroll-snap-type: bothは スナップ位置を各軸で独立して評価しますが、 一方の軸でのスナップ位置の選択が もう一方の軸のスナップ位置に影響することがあります。 例えば、一方の軸でスナップすると、 他方の軸で揃えるはずのスナップ領域が画面外になり、 そのスナップ位置は無効となり選択不可になります。
- scroll-paddingとscroll-marginのショートハンドが ロングハンドに値を割り当てる方法を明確化。 (Issue 1050)
-
スクロールスナップは特定の入力方法を義務付けないことを明確化。
(Issue 1305)
この仕様はUAがサポートするスクロール方法だけに適用されます。 UAに特定の入力やスクロール方法のサポートを義務付けるものではありません。
- 様々なスクロール操作に対するscroll-snap-stopの効果を明確化。 (Issue 1552)
- scroll-snap-stopは要素ごとのスナップ位置に 適用されるのであり、スクロールスナップコンテナ内のすべてのスナップ位置に 適用されるわけではないことを明確化。
- 例の文法エラー修正およびscroll-snap-typeセクションに新しい例を追加。 (Issue 827)
コメント処理状況が公開されています。