<link href="//maxcdn.bootstrapcdn.com/bootstrap/4.1.1/css/bootstrap.min.css" rel="stylesheet" id="bootstrap-css">
<script src="//maxcdn.bootstrapcdn.com/bootstrap/4.1.1/js/bootstrap.min.js"></script>
<script src="//cdnjs.cloudflare.com/ajax/libs/jquery/3.2.1/jquery.min.js"></script>
<!------ Include the above in your HEAD tag ---------->
<div class="container">
<div class="row">
<h2>smooth scrolling</h2>
<div class="controls">
<button onclick="scroll_down()">scroll down</button>
<button onclick="scroll_up()">scroll up</button>
</div>
<div class="container">
<p>
Dolor lacus. Lacus metus. Metus lorem litora. Fames purus felis eni parturient. Risus lacus a cras in eros fermentum facilisis netus et. Curae neque sed quis non nulla. Nulla magna sit massa neque dictum mi arcu litora fringilla integer proin. Nulla justo porta volutpat donec pellentesque hymenaeos etiam id mattis class. Curae vitae. Massa class per faucibus sodales nisl ac ultricies at mollis aliquam quisque magnis varius. Porta purus tempus rhoncus lacinia aenean ut.
Fames nulla tellus class facilisis blandit consectetuer sodales accumsan erat. Netus morbi pharetra fringilla nunc. Felis augue scelerisque ut turpis ultricies egestas semper. Fames purus convallis lorem diam penatibus. Porta augue est ipsum dolor fames erat nec. Felis neque volutpat justo lorem commodo non adipiscing. Proin augue diam habitant viverra ad dignissim condimentum. Porta massa fermentum cras. Neque nulla curae nullam morbi suspendisse ve varius. Proin lorem senectus felis a tellus venenatis non purus ridiculus vestibulum pretium cras. Dolor donec tempor parturient. Metus lacus. Fusce fames senectus vel amet. Dolor neque mollis netus eleifend vestibulum platea ante. Ipsum morbi congue molestie fames a quis adipiscing. Purus lacus congue purus aliquet interdum fames sagittis. Nulla velit. Lacus justo dictumst curabitur felis tincidunt lectus. Donec fames etiam semper sollicitudin facilisis montes. Etiam nulla vehicula massa auctor parturient dictumst. Neque curae quam suscipit nisl. Neque fames elit dapibus at orci netus.
Purus massa euismod mauris sem ut consectetuer. Fames ipsum ante tellus eu dictumst aliquam consectetuer mattis fames condimentum ultrices arcu ve. Felis augue volutpat ut felis nibh duis fermentum. Morbi purus. Justo porta mus duis vel rutrum ad torquent conubia neque ante sociis mi convallis ante aliquam. Morbi massa. Justo porta egestas imperdiet nibh hac. Etiam justo nunc aliquam quam donec auctor augue praesent. Magna dolor non arcu sollicitudin faucibus metus arcu justo odio. Felis augue. Augue dolor est amet lacinia etiam non semper habitant urna. Dolor ipsum. Netus lacus vel nam dui hac eu felis lorem dis eros ac. Proin nulla est felis nec lacus. Augue neque quisque. Risus augue fusce pede quis litora pulvinar hac conubia morbi.
Massa vitae per diam dictum mattis non sociis nulla. Augue fusce sociosqu vitae lorem sem euismod est vivamus mi metus ornare. Augue massa montes proin natoque ut cras. Nulla risus ipsum condimentum est at cras duis ipsum dictum et. Purus fusce. Fusce metus scelerisque nec auctor magnis facilisis. Purus lacus per pede eni pellentesque montes. Lacus netus ipsum natoque. Justo nulla nisl eu quis id porta luctus proin dignissim gravida nostra. Ipsum proin condimentum interdum dapibus duis velit quisque habitant cras. Purus massa. Curae magna pulvinar ve fames sit. Justo risus taciti mauris sed sociis auctor curae vestibulum ullamcorper nullam. Velit donec pulvinar etiam eget aptent in accumsan euismod.
</p>
</div>
</div>
</div>
div.controls {
padding: 10px 30px;
margin-bottom: 10px;
}
div.container {
height: 400px;
width: 300px;
overflow: scroll;
border: 1px solid blue;
}
div.container p {
font-size: 20px;
line-height: 2em;
margin-top: 0px;
}
function scroll_down() {
var el = document.querySelector('.container');
smooth_scroll_to(el, el.scrollTop + 200, 600);
}
function scroll_up() {
var el = document.querySelector('.container');
smooth_scroll_to(el, el.scrollTop - 200, 600);
}
/**
Smoothly scroll element to the given target (element.scrollTop)
for the given duration
Returns a promise that's fulfilled when done, or rejected if
interrupted
*/
var smooth_scroll_to = function(element, target, duration) {
target = Math.round(target);
duration = Math.round(duration);
if (duration < 0) {
return Promise.reject("bad duration");
}
if (duration === 0) {
element.scrollTop = target;
return Promise.resolve();
}
var start_time = Date.now();
var end_time = start_time + duration;
var start_top = element.scrollTop;
var distance = target - start_top;
// based on http://en.wikipedia.org/wiki/Smoothstep
var smooth_step = function(start, end, point) {
if(point <= start) { return 0; }
if(point >= end) { return 1; }
var x = (point - start) / (end - start); // interpolation
return x*x*(3 - 2*x);
}
return new Promise(function(resolve, reject) {
// This is to keep track of where the element's scrollTop is
// supposed to be, based on what we're doing
var previous_top = element.scrollTop;
// This is like a think function from a game loop
var scroll_frame = function() {
if(element.scrollTop != previous_top) {
reject("interrupted");
return;
}
// set the scrollTop for this frame
var now = Date.now();
var point = smooth_step(start_time, end_time, now);
var frameTop = Math.round(start_top + (distance * point));
element.scrollTop = frameTop;
// check if we're done!
if(now >= end_time) {
resolve();
return;
}
// If we were supposed to scroll but didn't, then we
// probably hit the limit, so consider it done; not
// interrupted.
if(element.scrollTop === previous_top
&& element.scrollTop !== frameTop) {
resolve();
return;
}
previous_top = element.scrollTop;
// schedule next frame for execution
setTimeout(scroll_frame, 0);
}
// boostrap the animation process
setTimeout(scroll_frame, 0);
});
}