“下拉显示”是一种界面模式,其中内容(例如搜索栏或刷新控件)在初始加载时隐藏在可滚动区域的顶部上方,用户可以下拉(向上滚动)来显示这些内容。此模式通常用于移动应用和 Web 应用中的搜索栏、过滤条件和其他次要控件,这些控件应该可供访问,但不会立即显示。
CSS 属性 scroll-initial-target 提供了一种仅使用 CSS 的声明式方法来实现此模式。通过在主要内容元素上设置 scroll-initial-target: nearest,滚动容器在呈现时会将隐藏的内容滚动到视图之外。以前,开发者依靠 JavaScript (Element.scrollIntoView()) 或网址片段标识符 (#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;
}
策略性实施和最佳实践
- 建议:如果您希望在加载时将用户的注意力吸引到可滚动区域的特定部分,并有意隐藏最顶部的搜索栏等外围界面单元,请使用
scroll-initial-target: nearest。 - 请勿将此与无障碍焦点混淆。此属性只会移动视觉视口,而不会移动键盘焦点。如果目标是键盘用户的起点,您必须手动管理
element.focus()。 - 如果您需要在加载时实现流畅的“滚动”动画,请不要使用此属性;此属性是离散的,会在布局阶段立即设置位置。
- 请勿在同一可滚动容器内的多个元素上设置
scroll-initial-target。如果多个元素指定了scroll-initial-target: nearest,浏览器会选择在 DOM 树顺序中首先出现的元素。 - 务必考虑优先级层次结构:网址片段(例如
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' });
}
}
});