行为的滚动持续时间 = 在不同浏览器中平滑

JT2*_*809 7 safari firefox opera chromium microsoft-edge

我想使用具有平滑行为的 window.scrollTo 函数。例如:

window.scrollTo({ top: 0, behavior: 'smooth' })
Run Code Online (Sandbox Code Playgroud)

并行我想改变元素的颜色。为此,我可以使用滚动事件来计算当前滚动位置的颜色。但这会导致性能不佳,因为滚动回调会经常调用。更好的解决方案是同时开始过渡。但为此我必须知道滚动持续时间。由于无法手动定义它,我需要知道浏览器使用的持续时间。

tre*_*mby 5

规范

滚动框使用用户代理定义的计时函数在用户代理定义的时间段内以平滑的方式滚动。用户代理应遵循平台约定(如果有)。

这立即使它成为一个复杂的问题,可能没有答案,或者至少没有可靠的答案。

浏览器可能

  • 瞄准目标速度而不是持续时间,因此如果要滚动多个页面,则滚动较长的时间
  • 如果许多嵌套滚动面板同时滚动,则调整滚动行为,例如将它们依次排序(我在 Chromium 中看到一些代码可能会执行类似的操作)
  • 允许用户对其进行配置,因此视力不佳或晕动病的人可以根据自己的喜好调整或禁用它
  • 遵循操作系统,它可能有自己的怪癖和自定义
  • 更改任何此内容,恕不另行通知,否则底层操作系统可能会

以下是一些 Firefox 代码中与平滑滚动相关的注释摘录。我没有深入研究这是否实际上与您正在做的滚动类型严格相关,但它提供了一个想法:

* |Smooth| scrolls have a symmetrical acceleration and deceleration curve
* modeled with a set of splines that guarantee that the destination will be
* reached over a fixed time interval.  |Smooth| will only be smooth if smooth
* scrolling is actually enabled.  This behavior is utilized by keyboard and
* mouse wheel scrolling events.
*
* |SmoothMsd| implements a physically based model that approximates the
* behavior of a mass-spring-damper system.  |SmoothMsd| scrolls have a
* non-symmetrical acceleration and deceleration curve, can potentially
* overshoot the destination on intermediate frames, and complete over a
* variable time interval.  |SmoothMsd| will only be smooth if cssom-view
* smooth-scrolling is enabled.
Run Code Online (Sandbox Code Playgroud)

这里有一些代码您可以用来自己测试。在我的实验中,我发现在 Firefox 和 Chromium 中,持续时间根据滚动距离而变化,而且我发现它们的速度不同。

* |Smooth| scrolls have a symmetrical acceleration and deceleration curve
* modeled with a set of splines that guarantee that the destination will be
* reached over a fixed time interval.  |Smooth| will only be smooth if smooth
* scrolling is actually enabled.  This behavior is utilized by keyboard and
* mouse wheel scrolling events.
*
* |SmoothMsd| implements a physically based model that approximates the
* behavior of a mass-spring-damper system.  |SmoothMsd| scrolls have a
* non-symmetrical acceleration and deceleration curve, can potentially
* overshoot the destination on intermediate frames, and complete over a
* variable time interval.  |SmoothMsd| will only be smooth if cssom-view
* smooth-scrolling is enabled.
Run Code Online (Sandbox Code Playgroud)
const qs = document.querySelector.bind(document);

const viewportHeightInput = qs("#viewport-height");
const contentHeightInput = qs("#content-height");
const viewport = qs("#viewport");
const content = qs("#content");
const output = qs("#output");

function update() {
  viewport.style.height = `${viewportHeightInput.value}px`;
  content.style.height = `${contentHeightInput.value}px`;
}
update();

viewportHeightInput.addEventListener("input", update);
contentHeightInput.addEventListener("input", update);

qs("#to-top").addEventListener("click", () => {
  start = performance.now();
  scrollEvents = 0;
  updateScrollEvents();
  viewport.scrollTo({
    behavior: "smooth",
    top: 0,
  })
});
qs("#to-bottom").addEventListener("click", () => {
  start = performance.now();
  scrollEvents = 0;
  updateScrollEvents();
  viewport.scrollTo({
    behavior: "smooth",
    top: viewport.scrollHeight - viewport.clientHeight,
  })
});

const scrollEventsOutput = qs("#scroll-events");
const elapsedOutput = qs("#elapsed");
let scrollEvents = 0;
let start = performance.now();
let last = null;
viewport.addEventListener("scroll", () => {
  last = performance.now();
  scrollEvents++;
  updateScrollEvents();
});

function updateScrollEvents() {
  scrollEventsOutput.value = scrollEvents;
  elapsedOutput.value = last == null ? 0 : last - start;
}
Run Code Online (Sandbox Code Playgroud)
#controls {
  display: grid;
  grid-template-columns: 10rem 1fr;
}

#controls fieldset {
  display: contents;
}

#viewport {
  overflow: auto;
  border: thick solid orange;
  margin: 4rem 0;
}

#content {
  background-image: linear-gradient(to bottom left, black, white);
  position: relative;
}

#content::before,
#content::after {
  position: absolute;
  left: 0;
  background-color: black;
  color: white;
  display: block;
}

#content::before {
  content: "start";
  top: 0;
}

#content::after {
  content: "end";
  bottom: 0;
}
Run Code Online (Sandbox Code Playgroud)