Chrome 129 以降では、JavaScript から scrollSnapChange
イベントと scrollSnapChanging
イベントを使用できます。組み込みのスナップイベントを実装することで、これまでは非表示だったスナップ状態が、適切なタイミングで、常に正確に操作可能になります。これらのイベントがなければ、このような便利な機能はありませんでした。
scrollSnapChange
より前は、インターセクション オブザーバーを使用してスクロールポートを横切る要素を見つけることができましたが、スナップされた要素を特定できるのは限られた状況に限られていました。たとえば、スナップ アイテムがスクロールポートを埋めるのか、スクロールポートの大部分を埋めるのかを検出できます。これを行うには、スクロール領域の交差する要素を監視し、スクロール領域の大部分を占有しているアイテムに基づいて、これがスナップ ターゲットであると想定し、scrollend
を待機して、スナップされたアイテム(スナップ ターゲット)に対してアクションを実行します。
ただし、scrollSnapChanging
より前は、スナップ ターゲットがいつ変更されたか、または何に変更されたか(スクロール フリングが行われたなど)を知ることはできませんでした。
これらの新しいイベントでは、このような情報をすばやく簡単に確認できます。これにより、スクロール スナップ インタラクションの現在の機能を超えて、スクロール スナップの関係と新しい UI フィードバック シナリオをオーケストレートできるようになります。
scrollSnapChange
このイベントは、スクロール ジェスチャーによって新しいスナップ ターゲットが停止された場合にのみ、次の順序で発生します。
- スクロールが停止した後。
scrollend
より前。
このイベントは、スクロールが完了したときに scrollend
の直前に発生します。ただし、新しいスナップ ターゲットに停止した場合に限られます。これにより、スクロール ジェスチャーが完了したときに、イベントが遅延またはジャストインタイムで発生するようになります。
scroller.addEventListener('scrollsnapchange', event => {
console.log(event.snapTargetBlock);
console.log(event.snapTargetInline);
})
scroller.onscrollsnapchange = event => {
console.log(event.snapTargetBlock);
console.log(event.snapTargetInline);
}
このイベントは、スナップされたアイテムをイベント オブジェクトの snapTargetBlock
と snapTargetInline
として公開します。スクロールが水平方向のみの場合は、snapTargetBlock
プロパティは null
になります。プロパティの値は要素ノードになります。
scrollSnapChange の固有の詳細
ユーザーがジェスチャーを解除するまでトリガーされない
画面上またはトラックパッドの上に指が残っている場合、ユーザーの操作によるスクロールが完了していないことを示します。つまり、スクロールが終了していないため、スナップ ターゲットがまだ変更されておらず、ユーザーの操作が完了するまで保留中です。
スナップ ターゲットが変更されていない場合、トリガーされません
このイベントはスナップの変更を対象としており、スナップ ターゲットが変更されていない場合、ユーザーがスクロール操作を行ったとしても、イベントは発生しません。ユーザーは実際にスクロールしたため、スクロールが完了すると scrollend
イベントがトリガーされます。
scrollSnapChanging
このイベントは、スクロール ジェスチャーによって新しいスナップ ターゲットが設定されたか、設定される予定であるとブラウザが判断した直後に発生します。スクロール中に即座に発生します。
scroller.addEventListener('scrollsnapchanging', event => {
console.log(event.snapTargetBlock);
console.log(event.snapTargetInline);
})
scroller.onscrollsnapchanging = event => {
console.log(event.snapTargetBlock);
console.log(event.snapTargetInline);
}
このイベントは、スナップされたアイテムをイベント オブジェクトの snapTargetBlock
と snapTargetInline
として公開します。スクロールが垂直方向のみの場合は、snapTargetInline
プロパティは null
になります。プロパティの値は要素ノードになります。
scrollSnapChanging の固有の詳細
スクロール ジェスチャー中に早い段階で頻繁に発生する
ユーザーのスクロール ジェスチャーが完了するのを待機する scrollSnapChange
とは異なり、このイベントはユーザーが指またはトラックパッドを使用してスクロールしているときに即座に発生します。指を離さずにゆっくりとスクロールしているユーザーの場合、ユーザーが複数のスナップ ターゲット上でパンしている限り、scrollSnapChanging
はジェスチャー中に複数回発動します。ユーザーがスクロールするたびに、ブラウザがリリース時に新しいスナップ ターゲットに停止すると判断した場合、その要素を示すイベントが発生します。
新しいスナップ ターゲットまでの経路にあるすべてのスナップ ターゲットがトリガーされない
また、ユーザーが複数のスナップ ターゲットにまたがるスクロール投げジェスチャーを一度に行うフリングについて考えてみましょう。このイベントは、停止するターゲットで 1 回トリガーされます。そのため、できるだけ早くスナップ ターゲットを提供しますが、無駄な処理は行いません。
ユースケースと例
これらのイベントにより、多くの新しいユースケースが可能になるとともに、現在のパターンを簡単に実装できるようになります。その一例が、スナップによってトリガーされるアニメーションの有効化です。スナップ アイテム、スナップ アイテムの子、またはスナップ ターゲットである場合に関連情報をコンテキストに応じて表示する。
次のパターンは、すぐに生産性を高めるのに役立つユースケースを示しています。
お客様の声をハイライト表示する
この例では、スナップされたお客様の声を宣伝または視覚的に強調しています。
scroller.onscrollsnapchange = event => {
scroller.querySelector(':scope .snapped')?.classList.remove('snapped')
event.snapTargetInline.classList.add('snapped')
}
スナップされたアイテムのキャプションを表示する
この例では、スナップされたアイテムのキャプションを示しています。このデモには両方のイベントが含まれているため、scrollSnapChange
と scrollSnapChanging
のタイミングとユーザー エクスペリエンスの違いを確認できます。
スナップされたプレゼンテーション スライドの子を 1 回アニメーション化する
この例では、新しいスライドが表示されて停止したときに、コンテンツを 1 回アニメーション化します。
document.addEventListener('scrollsnapchange', event => {
event.snapTargetBlock.classList.add('seen')
})
スクロールバーの x 軸と y 軸の両方でのスナップ
スクロール スナップは、水平方向と垂直方向のスクロールが可能なスクロールバーで機能します。このデモでは、グリッドをスクロールすると scrollSnapChanging
ターゲットと scrollSnapChange
ターゲットの両方が表示されます。このデモでは、ブラウザがスナップする要素が、想定している要素と一致しないことがあることを示します。
2 つのリンクされたスクロールバー
このデモには、2 つのスクロール スナップ コンテナがあります。1 つはリンクの概要リストで、もう 1 つは実際のページ分割コンテンツです。新しい scrollSnapChanging
イベントにより、これらのスナップ状態を双方向にリンクして、常に同期させることができます。
OKLCH カラー選択ツール
このデモには 3 つのスクロールバーがあり、それぞれ OKLCH の異なる色チャネルを表しています。スナップされたアイテムは、関連するラジオ グループと同期され、入力をラップするフォームからデータを取得できます。マウスまたはタップを使用するユーザーは、目的の値までスクロールできます。キーボードを使用している場合は、Tab キーと矢印キーを使用できます。スクリーン リーダーにとっては、単なるフォームです。
アニメーション ハブのずれとスナップ
このデモでは、scrollsnapchange
を使用してスナップがトリガーされる遷移で、スクロール スナップのエクスペリエンスを段階的に向上させています。
次の JavaScript を使用して、イベントのサポートを確認します。
if ('onscrollsnapchange' in window) {
// ok to use snap change
}
スクロール可能な定規入力
このデモでは、数値入力の長さを選択する代替方法として、スクロール可能な定規を備えています。数値入力欄に値を直接入力するか、サイズまでスクロールします。changing イベントは、ユーザーの操作中に選択を消去するために使用されます。change イベントは、状態を更新してユーザーの選択を確定するために使用されます。
カバーフロー
このデモは、有名な macOS のカバーフローをBramus Van Damme が再現した優れたスクロール駆動アニメーション(動画チュートリアルも)をベースにしています。scrollSnapChanging
はアルバム タイトルを非表示にするために、scrollSnapChange
はタイトルを表示するために使用されます。これらのイベントは、古いタイトルを早期に非表示にし、新しいタイトルを遅延して表示する際に役立ちます。
創造性を刺激するその他のアイデア
どの要素がスナップされるのか、どの要素がアクティブにスナップされているのかを簡単に把握できるようになったため、新しい可能性が広がりました。創造性を刺激するアイデアとその他のユースケースを以下に示します。
- 遅延読み込みのトリガー(スナップチェンジ トリガー レンダリングまたはデータ取得)。
- 大きな画像にリンクされたフィルムストリップのサムネイル。
- スナップされた動画のサムネイルで動画予告編の再生/一時停止を切り替える。
- アナリティクスのトラッキング
- スクロール ストーリーテリング
- ホイールオブフォーチュンの UI/UX
- スナップ ターゲットにアンカー付きのツールチップが表示されます。
- タップしてスナップ
- スナップして表示
- スナップ時の音
- スワイプ UI
- スワイプ可能なタブまたはカルーセル
さらなる研究
Chrome チームは、これらの新しい API を使ってどのようなアプリを構築するか、楽しみにしています。また、スクロール可能なエクスペリエンスの効率化に役立つことを願っています。