也许排名前五最让人讨厌的网站行为就是这个:你试图阅读一些内容(或点击某些东西!),突然页面在你下面移动(或者你误点了!)。有一个 CSS 属性可以帮助解决这个问题。此外,我们可以利用它来做一些以前只能用 JavaScript 实现的事情。
CSS 中的 overflow-anchor
属性 是相对较新的,它首次出现在 2017 年的 Chrome¹,2019 年的 Firefox,现在 Edge 也随着 Chrome 的过渡在 2020 年加入了这个属性。幸运的是,它的使用主要是一种增强。这个想法是,浏览器真的会尽力避免通过默认方式允许位置发生偏移。然后,如果你不喜欢它处理的方式,你可以用 overflow-anchor
关闭它。所以一般来说,你永远不会去触碰它。
但你可能已经猜到了,我们可以利用这个小巧的工具来做一些 CSS 小技巧。我们可以强制一个滚动元素即使添加了新内容也保持固定到底部。
我们希望在像 Slack 这样的 UI 中看到这种行为,如果我们滚动到某个频道中最新的消息,当有新消息到达时,它们会立即出现在底部,我们不必手动重新滚动到底部才能看到它们。
这个功能来自Ryan Hunt,他也感谢 Nicolas Chevobbe。
正如 Ryan 所说
你有没有尝试过实现一个可滚动的元素,在其中添加了新内容,并且你想将用户固定到底部?正确实现它并不容易。
至少,你需要用 JavaScript 检测何时添加了新内容,并强制滚动元素到最底部。以下是一种使用 JavaScript 中的 MutationObserver
来监视新内容并强制滚动的方法
const scrollingElement = document.getElementById("scroller");
const config = { childList: true };
const callback = function (mutationsList, observer) {
for (let mutation of mutationsList) {
if (mutation.type === "childList") {
window.scrollTo(0, document.body.scrollHeight);
}
}
};
const observer = new MutationObserver(callback);
observer.observe(scrollingElement, config);
这里有一个演示。
但我发现只有 CSS 的解决方案更诱人!上面的版本有一些我们将在后面讨论的用户体验缺陷。
这里的技巧是,浏览器默认情况下已经进行了滚动锚定。 但是浏览器试图做的不是在你身上移动页面。所以当添加了可能会改变页面视觉位置的新内容时,它们会尝试阻止这种情况发生。在这种不寻常的情况下,我们某种程度上想要相反的效果。我们希望页面被固定在页面的底部,并让视觉页面在视觉上移动,因为它被强制保持固定到底部。
以下是技巧的工作原理。首先,在滚动父元素中添加一些 HTML 代码
<div id="scroller">
<!-- new content dynamically inserted here -->
<div id="anchor"></div>
</div>
所有元素都自然地具有 overflow-anchor: auto;
,这意味着当它们出现在屏幕上时,它们会尝试阻止页面移动,但我们可以用 overflow-anchor: none;
来关闭它。所以诀窍是定位所有动态插入的内容并关闭它
#scroller * {
overflow-anchor: none;
}
然后只强制那个锚元素具有滚动锚定,其他元素则不具有
#anchor {
overflow-anchor: auto;
height: 1px;
}
现在,一旦那个锚元素出现在页面上,浏览器将被强制将滚动位置固定到它,并且因为它是在那个滚动元素中的最后一个元素,所以会保持固定到底部。
这里有两个小警告...
- 注意,锚必须具有一定的大小。我们在这里使用
height
来确保它不是一个大小为零的折叠/空元素,否则会阻止这个技巧起作用。 - 为了使滚动锚定起作用,页面必须至少滚动一次。
第二个问题更难解决。一种选择是完全不理会它,你可以等待用户滚动到底部,从那时起这个效果就会生效。这实际上很好,因为如果他们从底部滚动离开,这个效果就会停止工作,这也是你想要的。在上面的 JavaScript 版本中,请注意它如何强制你滚动到底部,即使你试图向上滚动, 这就是 Ryan 所说的“正确实现它并不容易”。
如果你需要立即启动这个效果,诀窍是让滚动元素立即变得可滚动,例如
body {
height: 100.001vh;
}
然后立即触发一个非常小的滚动
document.scrollingElement.scroll(0, 1);
这样应该可以解决问题。这些行可以在上面的演示中找到,可以取消注释并尝试。
- 说到 Chrome,Google 非常重视布局偏移问题。其中一个Web Core 指标是累积布局偏移 (CLS),它衡量视觉稳定性。如果你的 CLS 得分很低,它会直接影响你的 SEO。