一位读者给我发送了一个 GIF,展示了他们在 Google 移动端看到的酷炫效果。(可能是您在 Android 上启动 Chrome 时看到的首页?)页面中间有一个搜索输入框,它会随着页面滚动,但当它即将滚动出页面时,它会固定到页眉。让我们来了解一下,因为,你知道……
哦:我是一名前端开发人员,所以我基本上整天都在收到关于在滚动后将内容固定到顶部的请求
— Daniel Wilson (@dancwilson) 2014年9月16日
这是一个很酷的效果,尤其是在用于改善用户体验而不是固定一些愚蠢的侵入性广告时。这是我基于其想法制作的 GIF。有点卡顿,但想法在那里

两种状态
像大多数好的技巧一样,它并没有什么特别之处。我们所做的只是考虑(并设计)两种不同的可能状态
- 搜索栏在其可滚动位置
- 搜索栏在其固定的页眉位置
我们只需更改类名即可在它们之间切换。在不同的场景中显示两个搜索表单的技巧并没有什么用。这很好,因为我们不想围绕着保持它们同步而费力。只需移动一个就容易得多。
状态一

(我将在这里使用 SCSS,因为嵌套对于管理状态很有用。)
.top-header {
position: fixed;
top: 0;
left: 0;
width: 320px;
height: 60px;
}
.search { /* Container just in case we want more than just the search input to come along */
position: absolute;
top: 155px;
left: 20px;
right: 20px;
input {
width: 265px;
transition: width 0.2s;
-webkit-appearance: none; /* Autoprefixer doesn't catch this */
}
}
.top {
height: 250px; /* Space in here for search */
padding-top: 40px;
position: relative;
}
状态二

假设我们在父元素上添加了一个名为“fix-search”的类。
.top-header {
...
.fix-search & {
background: #eee;
}
}
.search { /* Container just in case we want more than just the search input to come along */
...
.fix-search & {
position: fixed;
top: 10px;
input {
width: 250px;
}
}
}
切换状态
这里的技巧是在恰当的时机应用该类。在我们的演示中,我们可以简单地测试完美的时机是什么,并将该时机硬编码到一些监视滚动的 JavaScript 中。jQuery 风格
var wrap = $("#wrap");
wrap.on("scroll", function(e) {
if (this.scrollTop > 147) {
wrap.addClass("fix-search");
} else {
wrap.removeClass("fix-search");
}
});
这就是在我们设置的两个状态之间切换所需的一切。如果页面向下滚动 147 像素或更多,则会应用该类。如果不是,则不会。即使您向下滚动然后向上滚动,该类也会消失(因为此小函数在每次滚动事件中都会被调用)。
演示
查看 CodePen 上 Chris Coyier 的 内容中的搜索框移动到固定页眉。(@chriscoyier) 在 CodePen 上。
去抖动
在每次演示将事件绑定到滚动事件时都提及滚动去抖动的伟大传统中:您应该考虑在将函数绑定到滚动事件时进行 去抖动,因为如果您不这样做,它将被调用无数次,并且速度可能会很慢。
CSS
这是那种仅用 CSS 就能轻松完成的事情。目前还没有想到什么好的解决方案,但我一直对人们使用 CSS 完成的疯狂事情感到惊讶,所以如果有什么新东西出现,我会更新它。
也许有一天,我们将能够进行滚动位置媒体查询?
固定定位支持
请注意,此演示依赖于固定定位,它在移动设备上的历史记录不稳定。虽然我很想说它现在“支持得很好”,但您应该自己做出判断。一些阅读材料
- Can I Use… 关于固定定位
- 移动浏览器中的固定定位 由 Brad Frost 撰写
- iOS 上固定位置和滚动的相关问题 由 Remy Sharp 撰写
这只是一个(不是特别可重用)示例
此演示中有很多 魔法数字。任何时候您设置高度时,大脑中都应该发出一些警告信号。这并不意味着永远不要这样做,只是意味着要小心。在此演示中,如果页眉中的居中图像高度发生变化,则无论如何看起来都会很奇怪。这不是最灵活和最宽容的布局。即使您修复了页眉以使其在更改后看起来正确,JavaScript 也具有相应的魔法数字来指示何时更改状态。
也许使用 waypoints(或其概念)的一些版本可以创建更可靠的系统。
好吧……我觉得没有更新。
JavaScript 是否仅在移动设备上滚动结束时触发?(我不知道如何称呼它,但您会明白的)
在 iOS 7 及更低版本上,是的,事件仅在滚动结束时触发。在 Chrome for Android 上不是,在 iOS 8 上也不是(需要测试最后一个)
没有看到 :/. 无论如何,学习到这些很酷
顺便说一句,他的 CodePen 在昨天安装的 iOS 7 上运行良好
Remy 有几个用于 **去抖动** 和 **节流** 的很好的函数,后者例如在调整大小时很有用。
这是 链接
position: sticky 将会实现它,但支持还不好:https://caniuse.cn/#feat=css-sticky
我最近在一个项目中被迫使用
position:sticky;
,因为滚动事件是在滚动结束时触发的 (https://developer.apple.com/library/safari/documentation/appleapplications/reference/SafariWebContent/HandlingEvents/HandlingEvents.html).在 iOS 7 上运行良好,但在 iOS 6 上不行。
看起来不错。这是一个将输入宽度调整大小和固定位置部分分开的版本,这样输入可以更好地“避开”菜单按钮。
三态版本
我喜欢它。 我 fork 了你的代码:相同的想法,但使用了一个中间的
top
位置,以便我可以缓和到其固定位置的过渡。顶部栏背景颜色也是如此。Chris,文章很棒。我在 Android Chrome 浏览器上注意到一个变化,那就是一旦窗口向上滚动,搜索栏就会淡出然后跳到顶部。我可能会稍微修改一下你的代码来重现这种效果。喜欢这个页面!
为了使代码更紧凑,您可以用以下代码替换
用
/Olaf
Chris 说
我非常希望看到一个 CSS 解决方案。许多网站使用滚动检测 JavaScript 来实现纯粹的装饰效果,而这些效果应该用 CSS 实现,或者为了性能目标(如延迟加载)。
媒体查询方法必须等到元素级媒体查询出现。我更倾向于使用
:onscreen
伪类。如果元素在视口中,则具有该伪类,并触发样式。在它滚动到屏幕上之前、整个页面在屏幕上之前(例如,在隐藏选项卡中打开的网页)或元素滚动出视图时,这些样式将被跳过。对于您的固定搜索栏,您需要将伪类附加到滚动消失的标题部分
对于延迟加载背景图像,您也可以使用出现在视图中的前一个同级元素,尽管您需要在它处于视图中时始终保持图像
对于元素滚动到视图中的动画效果,您只需在该元素上使用伪类
(也许伪类可以有一个参数,类似于 nth-of-type 参数,以便您可以限制效果是否每次元素进入视图时都发生或仅发生前几次?)
当我们梦想的时候,CSS 过渡中是否可以有一个
scroll
选项,这样您就不需要复杂的 JavaScript 来使同页面链接平滑滚动?设计师想要这些效果。设计师正在使用 JavaScript 创建这些效果。在 CSS 中创建一种声明式的方法来定义这些效果将允许浏览器对其进行优化。
好吧,我尝试了一些方法来移除魔法数字,但这并不简单。
http://codepen.io/Sirop/pen/qhsbA
您不能使用
offset().top
来消除魔法数字吗?还有……这是否与我们在粘性导航中看到的技术相同……当用户向下滚动页面一段距离后,这些导航会自动固定到屏幕顶部……我不太明白这怎么会是一件新鲜事……但我感谢这篇文章……非常有信息量……
我会假设这个网站上的任何内容都不是“新鲜事”。
这是实现基本粘性效果的一个很好的概述。如果您不想自己编写代码,有很多插件可以做到这一点。我成功使用了前面提到的 Waypoints(可以作为您自己滚动的一部分使用,但也有一个附加组件可以为您执行此操作),以及 ZURB Foundation 中的 sticky 类和 Sticky jQuery 插件,但是快速搜索一下肯定会在您所有喜欢的风格中找到替代方案。
一些最棒的设计创新都是通过“四处摸索”产生的。我希望这个比喻永远不会随着时间的推移而被遗忘。
不幸的是,
position: sticky
还没有实现。这种过渡是谷歌新的设计规范“Material Design”的一部分。Chrome 是首批支持此功能的 Android 应用之一。还有很多很酷的过渡和动画。它也可以用于 web 组件,网址是 polymer-project.org
对于那些谈论
position: sticky;
的人,这里是我使用纯 CSS 对 Chris 的示例进行的修改。请注意,它仅在 Firefox 32 中有效,这是目前稳定的版本。我绝对更喜欢没有魔法数字的版本。之前我为这种效果创建了一个模式,现在已经使用了几次。我解决的问题是:没有魔法数字,原始元素应该能够保留在文档流中,当原始元素变成固定位置元素时,页面内容不应该跳动,并且任何防止跳动的更改都应该本地化。在处理大型项目时,样式更改越本地化越好。
我通过在标记中将最终的粘性元素与一个“锚”元素配对来实现这一点。当粘性元素“粘住”时,我读取该元素的高度并将其赋予锚点以防止内容跳动。当取消粘性时,锚点的高度恢复为 0(或 auto,因为它应该是空的)。
这是一个例子
http://codepen.io/anon/pen/chDbg
到目前为止,我只将其用于将元素粘贴到页面顶部,但将其调整为粘贴到底部、左侧或右侧似乎非常简单。
Chris,想法不错,但是您是否在所有主要的浏览器(包括不同类型的屏幕分辨率)上测试过它?
感觉如果启用原生动量滚动,这可能无法正常工作。(我可能错了。还没有测试过。)
所以,如果我的“touchend”(滚动结束)发生在魔法数字 147px(或任何您的数字)以下,但动量将窗口滚动到顶部,“fix-search”类将不会被移除。
我理解对吗?如果是这样,有人有解决方案吗?
有趣的文章,它在所有浏览器上都测试过吗?
这就是我解决移除魔法数字问题的方法。我没有在 JQuery 代码段中使用预定义的高度,而是使用了
window.innerHeight
以及一个具有height: 100vh;
样式的 intro div。我在 CodePen 上放了一个示例。查看 CodePen 上 David Schroeder (@simpleminded) 编写的 Pen On Scroll Fix Content。
不过,这个问题的一个方面是我还没有完全测试它的响应性。使用 VH 单位的问题是,如果您也将其设置为 100% 宽,它会随着问题一起缩小,导致该框也缩小。此时,您必须使用预定义的数字来确保您的内容再次适合该框。
很棒的文章!我之前在一些网站上见过这个,当时并没有尝试,因为它看起来过于复杂。我觉得现在是时候尝试一下了!