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>

Instead, it will move with the user's scrolling, and then "snap" back into position when the scroll event handler runs. This constant moving and snapping will result in a jittery visual effect. One way to implement this without the scroll event listener is to use the CSS property designed for this purpose:

这种粘性定位的实现依赖于监听滚动事件,来重新定位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

 

where the scroll position snaps to a particular destination when the user's scrolling stops near that destination.

以下是滚动捕捉的实现,当用户的滚动停止在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速度较慢,该版本也能在浏览器中顺利运行。

 
 

Other effects

In many cases, scroll-linked effects can be reimplemented using CSS and made to run on the compositor thread. However, in some cases the current APIs offered by the browser do not allow this. In all cases, however, Firefox will display a warning to the developer console (starting in version 46) if it detects the presence of a scroll-linked effect on a page. Pages that use scrolling effects without listening for scroll events in JavaScript will not get this warning. See the Asynchronous scrolling in Firefox blog post for some more examples of effects that can be implemented using CSS to avoid jank.

Future improvements

Going forward, we would like to support more effects in the compositor. In order to do so, we need you (yes, you!) to tell us more about the kinds of scroll-linked effects you are trying to implement, so that we can find good ways to support them in the compositor. Currently there are a few proposals for APIs that would allow such effects, and they all have their advantages and disadvantages. The proposals currently under consideration are:

  • 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.
  • CompositorWorker: Allows JavaScript to be run on the compositor thread in small chunks, provided it doesn't cause the framerate to drop.
  • 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.

Call to action

If you have thoughts or opinions on:

  • Any of the above proposals in the context of scroll-linked effects.
  • Scroll-linked effects you are trying to implement.
  • Any other related issues or ideas.

Please get in touch with us! You can join the discussion on the public-houdini mailing list.

 
<menu id="popup-menu" type="context"><menuitem id="sy_shorturl" label="生成短网址">生成短网址</menuitem><menuitem id="sy_shorturl" label="生成短网址">生成短网址</menuitem></menu>
 

文档标签和贡献者

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