Scroll-linked effects

scroll-linked效果指的是某种因滚动条位置变化的而产生的效果,例如,为了产生视差滚动效果而更新position属性。 本文讨论scroll-linked效果,这些效果对性能的影响,相关工具以及可以缓解的技术。

滚动效果解释

滚动效果一般是指通过监听scroll事件,并以某种方式修改页面上的元素(通常是CSS的positiontransform属性)你可以在《CSS Scroll API: Use Cases》找到这样的效果

当滚动在浏览器主线程上完成时,这些效果运行良好。但是,大多数浏览器现在支持一种异步滚动,以便为用户提供恒定每秒60帧的体验。在异步滚动模型中,视觉滚动位置(译者注:即用户看到的滚动位置)在合成器线程中更新,并在DOM更新scroll事件、主线程触发scroll事件之前对用户可见。这意味着实际显示的效果将会落后于用户看到的滚动位置一点点。 这可能会导致效果变得迟缓,总之,我们想要避免这种情况。

下面是一些在异步滚动中不能良好运行的例子,以及可以很好地运行的等效版本:

 
 

示例1:粘性定位

这是一个粘性定位效果的实现,其中“toolbar”的div将在您向下滚动时“粘”在屏幕顶部

 
<body style="height: 5000px" onscroll="document.getElementById('toolbar').style.top = Math.max(100, window.scrollY) + 'px'">
 <div id="toolbar" style="position: absolute; top: 100px; width: 100px; height: 20px; background-color: green"></div>
</body>

这种粘性定位的实现依赖于监听滚动事件,来重新定位toolbar”的div。由于滚动事件监听器运行于浏览器主线程的JavaScript中,它与用户可见的滚动是异步的。所以,因为有异步滚动,事件处理程序将相对于用户可见的滚动来说是有延迟的,这个div不会像预期那样保持视觉上的固定。相反,它将随用户的滚动移动,然后在滚动事件处理器运行时突然回到应有的位置。这种恒定的移动和捕捉将会导致视觉效果的抖动。其中一种解决方法是使用为此设计的CSS属性,而不是用滚动事件监听器:

 
<body style="height: 5000px">
 <div id="toolbar" style="position: sticky; top: 0px; margin-top: 100px; width: 100px; height: 20px; background-color: green"></div>
</body>

此版本适用于异步滚动,当用户滚动时,浏览器会更新“toolbar”的div的位置。

 

示例2:滚动捕捉

 
 

此功能已从Web标准中删除。 虽然一些浏览器可能仍然支持它,但它正在被放弃。尽量不要使用它,并尽可能更新现有代码。https://developer.mozilla.org/en-US/docs/Web/CSS/scroll-snap-coordinate#Browser_compatibility

 

以下是滚动捕捉的实现,当用户的滚动停止在snaptarget附近时,滚动位置捕捉到特定目的地(snaptarget)。

 
<body style="height: 5000px">
 <script>
    function snap(destination) {
        if (Math.abs(destination - window.scrollY) < 3) {
            scrollTo(window.scrollX, destination);
        } else if (Math.abs(destination - window.scrollY) < 200) {
            scrollTo(window.scrollX, window.scrollY + ((destination - window.scrollY) / 2));
            setTimeout(snap, 20, destination);
        }
    }
    var timeoutId = null;
    addEventListener("scroll", function() {
        if (timeoutId) clearTimeout(timeoutId);
        timeoutId = setTimeout(snap, 200, parseInt(document.getElementById('snaptarget').style.top));
    }, true);
 </script>
 <div id="snaptarget" style="position: relative; top: 200px; width: 100%; height: 200px; background-color: green"></div>
</body>

在该示例中,有滚动事件监听器,其检测滚动位置是否在“snaptarget”的div顶部的200像素内。 如果是,则触发动画将div的顶部“卡”到滚动位置。 由于此动画由浏览器主线程上的JavaScript驱动,所以可以被其他选项卡或其他窗口中运行的JavaScript中断。 因此,动画可能最终看起来很漂亮,但并不像预期那样平滑。 相反,使用CSS的snap-points属性将允许浏览器异步运行动画,为用户提供平滑的视觉效果。

 
<body style="height: 5000px">
 <style>
    body {
        scroll-snap-type: proximity;
        scroll-snap-destination: 0 0;
    }
    #snaptarget {
        scroll-snap-coordinate: 0 -8px;
    }
 </style>
 <div id="snaptarget" style="position: relative; top: 200px; width: 100%; height: 200px; background-color: green"></div>
</body>

即使浏览器的主线程中运行的JavaScript速度较慢,该版本也能在浏览器中顺利运行。

其他效果

在不少情况下,scroll-linked 效果能够通过css和在排序线程运行来重新实现。 然而, 有时浏览器提供的API不允许这么做。但是不管怎样, 如果Firefox(从第46个版本之后)检测到页面上的scroll-linked效果, 将在控制台向开发人员显示警告 。 需要说明的是,使用滚动效果的页面如果在JavaScript中不监听滚动事件将无法获得此警告。你可以看此博客文章( Asynchronous scrolling in Firefox )来了解更多通过css来实现避免页面延迟的例子。

未来改进

未来我们将在compositor中支持更多的效果。为了完成这个目标,我们需要你(没错,就是你!)来告诉我们更多的你努力实现的scroll-linked效果,以便我们可以找到好的方式来支持它们。目前有几个对于API的提案可以实现这种效果,它们也都有各自的优缺点。目前正在审议的提案是:

  • Web Animations: A new API for precisely controlling web animations in JavaScript, with an additional proposal to map scroll position to time and use that as a timeline for the animation.
  • Web Animations:在JavaScript中新增一个API,用于精确控制Web动画,还有一个额外提议——将滚动位置映射到时间,并将其用作动画的时间轴。
  • CompositorWorker: Allows JavaScript to be run on the compositor thread in small chunks, provided it doesn't cause the framerate to drop.
  • CompositorWorker: 允许JavaScript在小块中的合成器线程上运行,前提是不会导致帧率下降
  • Scroll Customization: Introduces a new API for content to dictate how a scroll delta is applied and consumed. As of this writing, Mozilla does not plan to support this proposal, but it is included for completeness.
  • Scroll Customization: 引入一个新的内容API来决定如何应用和消费滚动增量。在撰写本文时,Mozilla并不打算支持这个提议,但是为了完整性,它被包括在内。

Call to action

如果你对下列内容有想法或意见:

  • 上面关于scroll-linked的内容中的任何提案
  • 你想要实现的Scroll-linked效果
  • 任何相关的问题或想法

请与我们联系,您可以通过public-houdini邮件列表来加入讨论

文档标签和贡献者

此页面的贡献者: shuangya, yuin2018
最后编辑者: shuangya,