在您的网站上滚动弹跳
已发表: 2022-03-10overscroll-behavior
于 2017 年 12 月在 Chrome 中实现,并于 2018 年 3 月在 Firefox 中实现,本文还介绍了该属性。 很好地理解这种效果对于构建或设计任何具有固定元素的网站非常有帮助。滚动弹跳(有时也称为滚动“橡皮筋”或“弹性滚动”)通常用于指您滚动到页面或 HTML 元素的最顶部或底部时看到的效果页面或元素,在使用触摸屏或触控板的设备上,并且在元素或页面弹回并将其自身对齐回到其顶部/底部(当您释放触摸/手指时)之前,可以看到空白区域。 您可以在元素之间的 CSS 滚动捕捉中看到类似的效果。
但是,本文重点介绍当您滚动到网页的最顶部或最底部时的滚动弹跳。 换句话说,当滚动端口到达其滚动边界时。
收集数据,强大的方式
你知道 CSS 可以用来收集统计数据吗? 事实上,甚至还有一种仅使用 CSS 的方法来使用 Google Analytics 跟踪 UI 交互。 阅读相关文章 →
很好地理解滚动弹跳非常有用,因为它将帮助您决定如何构建您的网站以及您希望页面如何滚动。
如果您不想在页面移动时看到fixed
元素,则不希望滚动弹跳。 一些示例包括:当您希望将页眉或页脚固定在某个位置时,或者如果您希望任何其他元素(例如菜单)被固定,或者如果您希望页面在滚动时的某些位置滚动对齐,并且您不希望在页面的最顶部或底部发生任何额外的滚动,这会使您网站的访问者感到困惑。 本文将针对在处理网页顶部或底部的滚动弹跳时所面临的问题提出一些解决方案。
我第一次遇到效果
当我更新我很久以前建立的网站时,我首先注意到了这种效果。 你可以在这里查看网站。 页面底部的页脚应该固定在页面底部的位置并且根本不动。 同时,您应该能够上下滚动页面的主要内容。 理想情况下,它会像这样工作:
它目前在 Firefox 或没有触摸屏或触控板的设备上的任何浏览器中以这种方式工作。 但是,当时我在 MacBook 上使用 Chrome。 当我发现我的网站无法正常工作时,我正在使用触控板滚动到页面底部。 你可以看到这里发生了什么:
不好了! 这不是应该发生的事情! 通过将其 CSS position
属性设置为fixed
,我将页脚的位置设置为页面底部。 这也是重新审视什么position: fixed;
是。 根据 CSS 2.1 规范,当“框”(在本例中为深蓝色页脚)固定时,它“相对于视口是固定的,并且在滚动时不会移动”。 这意味着当您上下滚动页面时,页脚不应该移动。 当我看到 Chrome 上发生的事情时,这让我很担心。
为了使本文更完整,我将在下面向您展示页面如何在 Mobile Edge、Mobile Safari 和 Desktop Safari 上滚动。 这与在 Firefox 和 Chrome 上滚动时发生的情况不同。 我希望这能让您更好地了解完全相同的代码当前如何以不同的方式工作。 目前,开发在不同 Web 浏览器上以相同方式工作的滚动是一项挑战。
寻找解决方案
我的第一个想法是,将有一种简单快捷的方法来解决所有浏览器上的这个问题。 这意味着我认为我可以找到一个只需要几行 CSS 代码并且不涉及 JavaScript 的解决方案。 因此,我做的第一件事就是尝试实现这一目标。 我用于测试的浏览器包括 macOS 和 Windows 10 上的 Chrome、Firefox 和 Safari,以及 iOS 上的 Edge 和 Safari。 这些浏览器的版本是撰写本文时的最新版本(2018 年)。
仅 HTML 和 CSS 解决方案
绝对和相对定位
我尝试的第一件事是使用绝对和相对定位来定位页脚,因为我习惯于这样构建页脚。 想法是将我的网页设置为 100% 高度,以便页脚始终位于页面底部并具有固定高度,而内容占用 100% 减去页脚高度,您可以滚动浏览它。 或者,您可以设置padding-bottom
而不是使用calc
并将body-container
高度设置为 100%,这样应用程序的内容就不会与页脚重叠。 CSS 代码看起来像这样:
html { width: 100%; height: 100%; overflow: hidden; position: relative; } body { width: 100%; margin: 0; font-family: sans-serif; height: 100%; overflow: hidden; } .body-container { height: calc(100% - 100px); overflow: auto; } .color-picker-main-container { width: 100%; font-size: 22px; padding-bottom: 10px; } footer { position: absolute; bottom: 0; height: 100px; width: 100%; }
该解决方案的工作方式与原始解决方案几乎相同(只是position: fixed;
)。 与此相比,此解决方案的一个优点是滚动不是针对整个页面,而是仅针对没有页脚的页面内容。 这种方法最大的问题是在 Mobile Safari 上,应用程序的页脚和内容同时移动。 这使得这种方法在快速滚动时非常有问题:
另一个我不想要的效果一开始很难注意到,我只是在尝试了更多的解决方案后才意识到它正在发生。 这是因为滚动浏览我的应用程序的内容稍微慢了一点。 因为我们将滚动容器的高度设置为自身的 100%,这会阻碍 iOS 上基于轻弹/动量的滚动。 如果该 100% 高度更短(例如,当 2000 像素的 100% 高度变为 900 像素的 100% 高度时),基于动量的滚动会变得更糟。 当您用手指轻拂触摸屏表面并且页面自行滚动时,就会发生基于轻拂/动量的滚动。 在我的例子中,我希望发生基于动量的滚动,以便用户可以快速滚动,所以我远离将高度设置为 100% 的解决方案。
其他尝试
网络上建议的解决方案之一,我尝试在我的代码中使用,如下所示作为示例。
html { width: 100%; position: fixed; overflow: hidden; } body { width: 100%; margin: 0; font-family: sans-serif; position: fixed; overflow: hidden; } .body-container { width: 100vw; height: calc(100vh - 100px); overflow-y: auto; -webkit-overflow-scrolling: touch; } .color-picker-main-container { width: 100%; font-size: 22px; padding-bottom: 10px; } footer { position: fixed; bottom: 0; height: 100px; width: 100%; }
此代码在 macOS 上的 Chrome 和 Firefox 上的工作方式与之前的解决方案相同。 这种方法的一个优点是滚动不限于 100% 高度,因此基于动量的滚动可以正常工作。 然而,在 Safari 上,页脚消失了:
在 iOS Safari 上,页脚变短,底部有一个额外的透明(或白色)间隙。 此外,滚动到最底部后,滚动页面的能力将丢失。 您可以在此处看到页脚下方的白色间隙:
您可能会看到很多有趣的代码行: -webkit-overflow-scrolling: touch;
. 这背后的想法是它允许对给定元素进行基于动量的滚动。 此属性在 MDN 文档中被描述为“非标准”和“不在标准轨道上”。 它在 Firefox 和 Chrome 中显示为正在检查的“无效属性值”,并且在桌面 Safari 中不显示为属性。 最后我没有使用这个 CSS 属性。
为了展示您可能遇到的另一个解决方案示例以及我发现的不同结果,我还尝试了以下代码:
html { position: fixed; height: 100%; overflow: hidden; } body { font-family: sans-serif; margin: 0; width: 100vw; height: 100vh; overflow-y: auto; overflow-x: hidden; -webkit-overflow-scrolling: touch; } .color-picker-main-container { width: 100%; font-size: 22px; padding-bottom: 110px; } footer { position: fixed; }
这实际上适用于不同的桌面浏览器,基于动量的滚动仍然有效,并且页脚固定在底部并且不会在桌面 Web 浏览器上移动。 也许这个解决方案最有问题的部分(以及它的独特之处)是,在 iOS Safari 上,页脚总是会轻微晃动和扭曲,并且您可以在滚动时看到其下方的内容。
使用 JavaScript 的解决方案
在尝试了一些仅使用 HTML 和 CSS 的初始解决方案后,我尝试了一些 JavaScript 解决方案。 我想补充一点,我不建议您这样做,最好避免这样做。 根据我的经验,通常有更优雅和简洁的解决方案只使用 HTML 和 CSS。 但是,我已经花了很多时间尝试其他解决方案,我认为快速查看是否有使用 JavaScript 的替代解决方案不会有什么坏处。
触摸事件
解决滚动弹跳问题的一种方法是阻止window
或document
上的touchmove
或touchstart
事件。 这背后的想法是阻止整个窗口上的触摸事件,而允许您要滚动的内容上的触摸事件。 像这样的代码示例如下所示:
// Prevents window from moving on touch on older browsers. window.addEventListener('touchmove', function (event) { event.preventDefault() }, false) // Allows content to move on touch. document.querySelector('.body-container').addEventListener('touchmove', function (event) { event.stopPropagation() }, false)
我尝试了此代码的许多变体以尝试使滚动正常工作。 阻止window
上的touchmove
没有任何区别。 使用document
没有任何区别。 我也尝试使用touchstart
和touchmove
来控制滚动,但这两种方法也没有区别。 我了解到,出于性能原因,您不能再以这种方式调用event.preventDefault()
。 您必须在事件侦听器中将passive
选项设置为false
:
// Prevents window from moving on touch on newer browsers. window.addEventListener('touchmove', function (event) { event.preventDefault() }, {passive: false})
图书馆
您可能会遇到一个名为“iNoBounce”的库,该库旨在“阻止您的 iOS Web 应用在滚动时弹跳”。 现在使用这个库来解决我在本文中描述的问题时需要注意的一点是,它需要您使用-webkit-overflow-scrolling
。 另一件需要注意的事情是,我最终得到的更简洁的解决方案(稍后将描述)与 iOS 上的功能类似。 您可以通过查看其 GitHub 存储库中的示例来自行测试,并将其与我最终得到的解决方案进行比较。
过度滚动行为
在尝试了所有这些解决方案之后,我发现了 CSS 属性overscroll-behavior
。 overscroll-behavior
CSS 属性于 2017 年 12 月在 Chrome 63 和 2018 年 3 月在 Firefox 59 中实现。如 MDN 文档中所述,此属性“允许您控制浏览器的滚动溢出行为——当已到达滚动区域。” 这是我最终使用的解决方案。
我所要做的就是在我的网站body
中将overscroll-behavior
设置为none
,然后我可以将页脚的position
保留为fixed
。 尽管基于动量的滚动应用于整个页面,而不是没有页脚的内容,但这个解决方案对我来说已经足够好了,并且满足了我当时的所有要求,并且我的页脚不再在 Chrome 上意外反弹。 值得注意的是,Edge 现在将此属性标记为正在开发中。 如果浏览器尚不支持overscroll-behavior
,则可以将其视为一种增强。
结论
如果您不希望您的固定页眉或页脚在您的网页上反弹,您现在可以使用overscroll-behavior
CSS 属性。
尽管该解决方案在不同浏览器中的工作方式不同(页面内容的弹跳仍然会在 Safari 和 Edge 上发生,而在 Firefox 和 Chrome 上则不会),但当您滚动到最顶部时,它会保持页眉或页脚不变或网站底部。 这是一个简洁的解决方案,在所有经过测试的浏览器上,基于动量的滚动仍然有效,因此您可以非常快速地滚动浏览大量页面内容。 如果您要在网页上构建固定的页眉或页脚,则可以开始使用此解决方案。