I want to make a page scroll down slowly and smoothly. Well, the speed should actually adjustable. The user should also be able to scroll up manually while the script is scrolling down. First I tried this:
var autoScrollDelay = 1
var autoScrollSpeed = 1
var autoScrollTimer
function setAutoScroll(newValue) {
autoScrollSpeed = newValue ? newValue : autoScrollSpeed
if (autoScrollTimer) {
clearInterval(autoScrollTimer)
}
if (autoScrollDelay) {
autoScrollTimer = setInterval(function(){
window.scrollBy(0,autoScrollSpeed)
},autoScrollDelay)
}
}
setAutoScroll(1) // higher number = faster scrolling
But it was causing a very heavy CPU load and the slowest speed was too fast. And in addition to that manually scrolling up did not work properly while the code was running.
Then I tried:
var autoScrollDelay = 1
var autoScrollSpeed = 1
var autoScrollTimer
function setAutoScroll(newValue) {
autoScrollDelay = newValue ? newValue : autoScrollDelay //using autoScrollDelay instead of autoScrollSpeed
if (autoScrollTimer) {
clearInterval(autoScrollTimer)
}
if (autoScrollDelay) {
autoScrollTimer = setInterval(function(){
window.scrollBy(0,autoScrollSpeed)
},autoScrollDelay)
}
}
setAutoScroll(200) // higher number scrolls slower
But the scrolling was not smooth when setting it too slow (e.g. 200).
Then I tried:
$("html, body").animate({
scrollTop: $('html, body').get(0).scrollHeight,
}, 40000, "linear");
But again the CPU load was unreasonably high and scrolling up or down manually wasn't possible this way.
Is there a better way to do this?
Here is one possible implementation. The refresh rate is fixed, and corresponds to fps
in the code below. To make sure that the speed is constant, I consider the time elapsed since the previous scroll when calculating the new scroll position. Manual scrolling is allowed (with the scroll bar, with the mouse wheel, or with touch on mobile devices) and taken into account by processing scroll
, wheel
and touchmove
events. You can see the code at work in this codepen.
var fps = 100;
var speedFactor = 0.001;
var minDelta = 0.5;
var autoScrollSpeed = 10;
var autoScrollTimer, restartTimer;
var isScrolling = false;
var prevPos = 0, currentPos = 0;
var currentTime, prevTime, timeDiff;
window.addEventListener("scroll", function (e) {
// window.pageYOffset is the fallback value for IE
currentPos = window.scrollY || window.pageYOffset;
});
window.addEventListener("wheel", handleManualScroll);
window.addEventListener("touchmove", handleManualScroll);
function handleManualScroll() {
// window.pageYOffset is the fallback value for IE
currentPos = window.scrollY || window.pageYOffset;
clearInterval(autoScrollTimer);
if (restartTimer) {
clearTimeout(restartTimer);
}
restartTimer = setTimeout(() => {
prevTime = null;
setAutoScroll();
}, 50);
}
function setAutoScroll(newValue) {
if (newValue) {
autoScrollSpeed = speedFactor * newValue;
}
if (autoScrollTimer) {
clearInterval(autoScrollTimer);
}
autoScrollTimer = setInterval(function(){
currentTime = Date.now();
if (prevTime) {
if (!isScrolling) {
timeDiff = currentTime - prevTime;
currentPos += autoScrollSpeed * timeDiff;
if (Math.abs(currentPos - prevPos) >= minDelta) {
isScrolling = true;
window.scrollTo(0, currentPos);
isScrolling = false;
prevPos = currentPos;
prevTime = currentTime;
}
}
} else {
prevTime = currentTime;
}
}, 1000 / fps);
}
setAutoScroll(20);
The function from this article uses vanilla JS to implement smooth scrolling at various speeds. Here is a demo:
document.getElementById("scrollBottomButton").onclick = function() {
var duration = document.getElementById("bottomScrollDuration").value * 1000;
scrollIt(document.querySelector("#bottom-row"), duration, "easeOutQuad");
};
document.getElementById("scrollTopButton").onclick = function() {
var duration = document.getElementById("topScrollDuration").value * 1000;
scrollIt(document.getElementById("top-row"), duration, "easeOutQuad");
};
// thanks to https://pawelgrzybek.com/page-scroll-in-vanilla-javascript/
function scrollIt(destination, duration = 200, easing = "linear", callback) {
const easings = {
linear(t) {
return t;
},
easeOutQuad(t) {
return t * (2 - t);
}
};
const start = window.pageYOffset;
const startTime = "now" in window.performance
? performance.now()
: new Date().getTime();
const documentHeight = Math.max(
document.body.scrollHeight,
document.body.offsetHeight,
document.documentElement.clientHeight,
document.documentElement.scrollHeight,
document.documentElement.offsetHeight
);
const windowHeight =
window.innerHeight ||
document.documentElement.clientHeight ||
document.getElementsByTagName("body")[0].clientHeight;
const destinationOffset = typeof destination === "number"
? destination
: destination.offsetTop;
const destinationOffsetToScroll = Math.round(
documentHeight - destinationOffset < windowHeight
? documentHeight - windowHeight
: destinationOffset
);
if ("requestAnimationFrame" in window === false) {
window.scroll(0, destinationOffsetToScroll);
if (callback) {
callback();
}
return;
}
function scroll() {
const now = "now" in window.performance
? performance.now()
: new Date().getTime();
const time = Math.min(1, (now - startTime) / duration);
const timeFunction = easings[easing](time);
window.scroll(
0,
Math.ceil(timeFunction * (destinationOffsetToScroll - start) + start)
);
if (window.pageYOffset === destinationOffsetToScroll) {
if (callback) {
callback();
}
return;
}
requestAnimationFrame(scroll);
}
scroll();
}
// scroll testing
var middleHtml = [];
const schiller = "Nur Beharrung führt zum Ziel, Nur die Fülle führt zur Klarheit, Und im Abgrund wohnt die Wahrheit.".split(' ')
for(var i=0; i<schiller.length;i+=1){
middleHtml.push("<div class=' container row' id='scrolling'><h1 style='margin: 30rem 10rem 30rem 0;font-size: 3.5em;font-family: Helvetica, sans-serif;color: #fff;'>"+schiller[i]+"</h1></div>");
}
document.getElementById('middle').innerHTML = middleHtml.join('');
.container-fluid {
background: #e52d27;
background: -webkit-linear-gradient(to top, #b31217, #e52d27);
background: linear-gradient(to top, #b31217, #e52d27);
}
.container-fluid input, .container-fluid .btn {
border-radius: 0;
}
.btn {
background: rgba(210,200,200,0.95);
}
<link href="https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/4.0.0-alpha.6/css/bootstrap.min.css" rel="stylesheet"/>
<link href="https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/4.0.0-alpha.6/css/bootstrap.min.css" rel="stylesheet"/>
<div class='container-fluid'>
<div class='row' id='top-row'>
<div class='col-sm-8'>
<input class='form-control' id='bottomScrollDuration' placeholder='Enter duration in seconds (4, 25, 40, etc...)' />
</div>
<div class='col-sm-4'>
<button class='btn' id='scrollBottomButton'>Scroll to bottom</button>
</div>
</div>
<div id='middle'>
</div>
<div class='row' id='bottom-row'>
<div class='col-sm-8'>
<input class='form-control' id='topScrollDuration' placeholder='Enter duration in seconds (4, 25, 40, etc...)' />
</div>
<div class='col-sm-4'>
<button class='btn' id='scrollTopButton'>Scroll to top</button>
</div>
</div>
</div>
See CodePen Demo
Update
You could try this if you just want to adjust the speed and keep a constant scrolling behavior:
function pageScroll(speed) {
window.scrollBy(0,1);
scrolldelay = setTimeout(pageScroll,speed);
}
And then call the function with a speed of your choice i.e.:
pageScroll(1);
I ran it in Chrome, and it didn't tax my CPU usage. The CPU does spike more when it's run in Firefox.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With