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

Scroll duration for behaviour = smooth in different browsers

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

window.scrollTo({ top: 0, behavior: 'smooth' })

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

我在评论中分享的代码示例仅供参考。您还需要根据自己的滚动页面需求修改代码。

在这里,我尝试修改那个示例代码来滚动页面。

$(window).scroll(function() {
  
  // selectors
  var $window = $(window),
      $body = $('body'),
      $panel = $('.panel');
  
  // Change 33% earlier than scroll position so colour is there when you arrive.
  var scroll = $window.scrollTop() + ($window.height() / 3);
 
  $panel.each(function () {
    var $this = $(this);
    
    // if position is within range of this panel.
    // So position of (position of top of div <= scroll position) && (position of bottom of div > scroll position).
    // Remember we set the scroll to 33% earlier in scroll var.
    if ($this.position().top <= scroll && $this.position().top + $this.height() > scroll) {
          
      // Remove all classes on body with color-
      $body.removeClass(function (index, css) {
        return (css.match (/(^|\s)color-\S+/g) || []).join(' ');
      });
       
      // Add class of currently active div
      $body.addClass('color-' + $(this).data('color'));
    }
  });    
  
}).scroll();

$(document).ready(function(){
  $("button").click(function(){
     $("html, body").animate({
      scrollTop: $("#bottom").offset().top - 220
    }, 8000);
  // document.getElementById('bottom').scrollIntoView({behavior: "smooth"});
  });
});
/* Setting fade transition and default settings */
body {
  color: #000;
  background-color: #f4f4f4;
  transition: background-color 1s ease;
}

/* panel styles */
.panel {
  /* min height incase content is higher than window height */
  min-height: 100vh;
  display: flex;
  justify-content: space-around;
  align-items: center;
  font-family: sans-serif;
  /* outline: 10px solid hotpink; */
  /* turn above on to see the edge of panels */
}

/* colours */
.color-violet {
  background-color: #7A4EAB;
}
.color-indigo {
  background-color: #4332CF;
}
.color-blue {
  background-color: #2F8FED;
}
.color-green {
  background-color: #4DCF42;
}
.color-yellow {
  background-color: #FAEB33;
}
.color-orange {
  background-color: #F19031;
}
.color-red {
  background-color: #F2293A;
}

/* styling for demo, can ignore */
body {
  text-align: center;
  font-size: 120%;
  line-height: 1.618;
}
h1, h2 {
  font-size: 3em;
  letter-spacing: -0.05em;
  line-height: 1.1;
}
p {
  max-width: 30em;
  margin-bottom: 1.618em;
}
a {
  color: #4332CF;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/2.2.4/jquery.min.js"></script>


<div class="panel" data-color="white">


    <div>
            <h1>scrolling example</h1>
      <div><button>Click me to scroll to bottom</button></div>
  </div>
</div>
<div class="panel" data-color="violet">
  <h2>Violet panel</h2>
</div>
<div class="panel" data-color="indigo">
  <h2>Indigo panel</h2>
</div>
<div class="panel" data-color="blue">
  <h2>Blue panel</h2>
</div>
<div class="panel" data-color="green">
  <h2>Green panel</h2>
</div>
<div class="panel" data-color="yellow">
  <h2>Yellow panel</h2>
</div>
<div class="panel" data-color="orange">
  <h2>Orange panel</h2>
</div>
<div class="panel" data-color="red">
  <h2>Red panel</h2>
</div>
<div id="bottom"></div>

MS Edge Chromium 浏览器中的输出:

此外,您可以尝试根据您的要求修改代码示例。

参考:

Code example link

The specification

The scrolling box is scrolled in a smooth fashion using a user-agent-defined timing function over a user-agent-defined period of time. User agents should follow platform conventions, if any.

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

浏览器可能

  • 瞄准目标速度而不是持续时间,因此如果有多个页面要滚动,则滚动更长的时间
  • 如果许多嵌套的滚动面板同时滚动,请调整滚动行为,例如一个接一个地排列它们(我看到 some code in Chromium 可能会做这样的事情)
  • 允许user-configurable,这样视力不佳或晕车的人可以根据自己的喜好调整它,或禁用它
  • 遵从操作系统,它可能有自己的怪癖和定制
  • 更改其中任何一项,恕不另行通知,否则潜在的 OS 可能

这是 some Firefox code 中有关平滑滚动的评论的摘录。我没有深入研究这是否真的与你正在做的那种卷轴严格相关,但它给出了一个想法:

* |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.

这里有一些代码供您自己测试。在我的实验中,我发现在 Firefox 和 Chromium 中,持续时间会根据滚动的距离而变化,而且我在每一个中都看到了不同的速度。

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;
}
#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;
}
<div id="controls">
  <fieldset>
    <label for="viewport-height">Viewport height</label>
    <input id="viewport-height" type="number" min="1" value="400">
  </fieldset>
  <fieldset>
    <label for="content-height">Content height</label>
    <input id="content-height" type="number" min="1" value="1000">
  </fieldset>
  <fieldset>
    <label>Triggers</label>
    <ul>
      <li><button id="to-top">Scroll to top</button></li>
      <li><button id="to-bottom">Scroll to bottom</button></li>
    </ul>
  </fieldset>
  <fieldset>
    <label for="scroll-events">Scroll events</label>
    <input id="scroll-events" type="number" readonly value="0">
  </fieldset>
  <fieldset>
    <label for="elapsed">Milliseconds between start of scroll and last scroll event</label>
    <input id="elapsed" type="number" readonly value="0">
  </fieldset>
</div>

<div id="viewport">
  <div id="content"></div>
</div>