JSFiddle - React, Tailwind, and code Playground
by termi
HTML
<div class="scrollTopOrBottom">↑↓</div>
<main>
<header>
Scrolling Demo
</header>
<section>
<a href="#footer">Scroll to footer</a>
<a href="#textEnd">Scroll to text end</a>
<div>
<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Suspendisse lacinia urna nibh, ut porta odio lobortis et. Nam tincidunt quam ac odio rhoncus, in eleifend nisi adipiscing. Etiam mollis lorem in nulla iaculis volutpat. Nunc vehicula sed odio ut convallis. Maecenas id purus facilisis, dapibus elit vitae, consectetur lorem. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia Curae; In hac habitasse platea dictumst. Sed eget sodales orci, fermentum varius erat. Aenean malesuada leo eros, ac imperdiet odio suscipit in. Phasellus at nisl accumsan neque aliquam imperdiet. Donec molestie lacus id ultricies malesuada. Ut accumsan tellus in turpis pretium dignissim. Vestibulum metus tellus, consequat a lorem sit amet, volutpat sollicitudin nibh. Quisque ut dui sagittis arcu blandit rhoncus ut sit amet tellus.
</p><br /><p>
Proin vel nibh id justo malesuada feugiat. Duis feugiat malesuada lacus. Proin tincidunt porttitor elementum. Morbi at augue et ante vehicula dictum. Praesent mattis nibh vel dui sodales iaculis. Curabitur est lacus, venenatis eget blandit nec, condimentum eget orci. Aliquam neque est, varius quis quam ac, iaculis tempus risus. Sed vestibulum dapibus varius. Proin scelerisque neque sed sem porttitor, at consectetur felis lobortis. Nulla tempus turpis nisi.
</p><br /><p>
Sed vel mauris vitae augue elementum tincidunt vel ac lacus. Aliquam erat volutpat. Maecenas dignissim nisl massa, a accumsan nunc euismod vitae. Integer commodo risus a justo ultrices, condimentum lacinia dui posuere. Suspendisse potenti. Donec venenatis placerat est, ac vestibulum metus porta in. Fusce adipiscing mi in metus interdum, eu porttitor justo aliquam. Vivamus egestas velit...
CSS
body {
position: relative;
}
main {
display: block;
height: 2200px;
position: relative;
width: 400px;
}
.scrollTopOrBottom {
position: fixed;
top: 50%;
right: 0;
margin-top: -20px;
width: 20px;
height: 20px;
padding: 20px;
background: black;
color: white;
border-radius: 10px 0 0 10px;
cursor: pointer;
}
section {
background: gray;
padding: 20px;
}
footer {
position: absolute;
bottom: 0;
left: 0;
right: 0;
height:60px;
background: green;
}
JavaScript
//cubic-bezier timing function
var lineanBezier=function(q,w,e,r){function b(d,g,i,h){this.b={x:d,y:g};this.c={x:i,y:h}}function c(d,g,i){var h=3*g,g=3*(i-g)-h;
return(((1-h-g)*d+g)*d+h)*d}b.prototype.get=function(d){var g=this;if(0==d||1==d)return{x:d,y:d};if(!(0<d)||!(1>d))throw new RangeError;
return{x:c(d,g.b.x,g.c.x),y:c(d,g.b.y,g.c.y)}};return new b(q,w,e,r)}(1,1,1,1);
var eventHandlerObject = {
scrollTimer: null
, time: 500
, step: 25
, doAnimateScroll: function(cur, start, alpha) {
clearTimeout(this.scrollTimer);
cur += this.step;
if(cur < this.time)
this.scrollTimer = setTimeout(this.doAnimateScroll.bind(this, cur, start, alpha), this.step);
window.scrollTo(window.pageXOffset, start + alpha * lineanBezier.get(cur / this.time).y);
}
, handleEvent: function(e) {
var target = e.target
, action
, scrollToElement
;
if( target.nodeName == "A" ) {
action = target.href;
if( action = action.match(/#(\w+)/) ) {
if( scrollToElement = document.getElementById(action[1]) ) {
this.doAnimateScroll(
0,
window.pageYOffset,
scrollToElement.offsetTop + scrollToElement.offsetHeight - window.innerHeight - window.pageYOffset
);
e.preventDefault();
}
}
}
else if( target.classList.contains("scrollTopOrBottom") ) {
action = document.documentElement.getBoundingClientRect();
action = action.height / 2 < ((action.height - action.bottom) + document.documentElement.clientHeight / 2) ?
0
:
action.height
;
this.doAnimateScroll(
0,
window.pageYOffset,
action - window.pageYOffset
);
}
...