「プルして表示」は、コンテンツ(検索バーや更新コントロールなど)が最初の読み込み時にスクロール可能な領域の上部に隠れており、ユーザーが下にプル(上にスクロール)すると表示される UI パターンです。このパターンは、モバイルアプリやウェブアプリで、検索バー、フィルタ、その他のセカンダリ コントロールなど、アクセス可能であるものの、すぐには表示されないようにする必要があるコントロールによく使用されます。
CSS プロパティ scroll-initial-target を使用すると、CSS のみでこのパターンを宣言的に実装できます。メイン コンテンツ要素に scroll-initial-target: nearest を設定すると、スクロール コンテナは、隠しコンテンツがスクロールされて表示されない状態でレンダリングされます。以前は、デベロッパーは JavaScript(Element.scrollIntoView())または URL フラグメント識別子(#content-id)を使用してこれを実現していましたが、どちらにも制限があり、実装が複雑でした。
実装方法
プルして表示パターンを実装するには:
- スクロール コンテナを確保する: ターゲット要素は、スクロール コンテナ(
overflow: autoなど、スクロールを可能にするオーバーフローがある要素)内にある必要があります。これは、ルート<html>要素を含む任意の祖先要素にすることができます。 - 非表示要素を定義する: 非表示にするコンテンツ(検索バーなど)を、スクロール コンテナ内の最初の子孫として配置します。この要素は、最初の読み込み時にビュー外にスクロールされます。
- メイン コンテンツを定義する: メイン コンテンツ要素を非表示要素の直後に配置します。これは、ユーザーに最初に表示される要素です。
- メイン コンテンツをターゲットにする: メイン コンテンツ要素に
scroll-initial-target: nearestを適用して、スクロール コンテナがスクロールされて表示され、その上の要素が非表示になるようにします。 - スクロール スナップを追加する: 非表示の要素が常に完全に表示されるか、完全に非表示になるように(部分的にスクロールされた状態にならないように)するには、スクロール コンテナに
scroll-snap-type: y mandatoryを追加し、非表示の要素とメイン コンテンツ要素の両方にscroll-snap-align: startを追加します。
コードの例: プルして検索を表示する
/**
* ANCESTOR: Define the scroll container.
* Scroll snapping ensures the search bar is always
* either fully visible or fully hidden.
*/
.scroll-container {
height: 100vh;
overflow-y: auto;
scroll-snap-type: y mandatory;
}
/**
* HIDDEN ELEMENT: The search bar hidden above the fold on load.
* It has scroll-snap-align so it snaps into place when pulled down.
*/
.search-bar {
height: 60px;
scroll-snap-align: start;
}
/**
* MAIN CONTENT + TARGET: The element the user sees first.
* scroll-snap-align makes it a valid snap point.
* scroll-initial-target tells the browser to scroll here on
* initial render, hiding the search bar above it.
*/
.main-content {
scroll-snap-align: start;
scroll-initial-target: nearest;
}
戦略的な実装とベスト プラクティス
- 推奨: 読み込み時にスクロール可能領域の特定の部分にユーザーの注意を引き、最上部の検索バーなどの周辺 UI ユニットを意図的に非表示にする場合は、
scroll-initial-target: nearestを使用します。 - ユーザー補助フォーカスと混同しないでください。このプロパティは、ビジュアル ビューポートのみを移動します。キーボード フォーカスは移動しません。ターゲットがキーボード ユーザーの開始点となる場合は、
element.focus()を手動で管理する必要があります。 - 読み込み時にスムーズな「スクロール」アニメーションが必要な場合は、使用しないでください。このプロパティは離散的であり、レイアウト フェーズ中に位置を即座に設定します。
- 同じスクロール可能なコンテナ内の複数の要素に
scroll-initial-targetを設定しないでください。複数の要素でscroll-initial-target: nearestが指定されている場合、ブラウザは DOM ツリーの順序で最初に表示される要素を選択します。 - 優先順位を考慮する: URL フラグメント(例:
example.com/#top)とコンテナレベルのscroll-startプロパティは、どちらもscroll-initial-targetよりも優先されます。
代替戦略
API をまだサポートしていないブラウザでは、JavaScript のフォールバックを使用します。コンテンツをプルして表示する場合、メイン コンテンツをコンテナの start(上部)にバインドする必要があります。
/**
* Progressive Enhancement Fallback
*/
document.addEventListener("DOMContentLoaded", () => {
// Check for native CSS support
if (!CSS.supports("scroll-initial-target", "nearest")) {
const targetContent = document.querySelector('.main-content.target');
if (targetContent) {
// Use behavior: "instant" to mimic the native CSS behavior
// 'block: start' should match your CSS 'scroll-snap-align' (or expected top position)
targetContent.scrollIntoView({ behavior: 'instant', block: 'start' });
}
}
});