Reputation: 249
We know what "scroll-behavior: smooth" does, but what is the default transition time for this behavior? Or is it relative?
Upvotes: 3
Views: 4521
Reputation: 392
The specification says
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.
Right away that makes it a complicated question to which there is likely no answer, or at least no answer which will reliably stay put.
Browsers might
Here is an excerpt of a comment in some Firefox code to do with smooth scrolling. I did not dig in to whether this is actually strictly relevant to the sorts of scroll you are doing, but it gives an idea:
|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.
And here is a little bit of code you can use to test for yourself. In my experimentation I'm seeing the duration varying based on how far it scrolls, both in Firefox and Chromium, and I'm seeing different speeds in each of those.
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>
Upvotes: 4