Super Smooth Simple Scrolling

by Eugeny Venegrad

HTML

<div class="high" id="top">
  <button id="scrollMid">scroll to middle</button>
  Lorem ipsum dolor sit amet, consectetur adipiscing elit. Donec ultricies mauris arcu, vitae tristique orci viverra eget. Aliquam suscipit metus sed luctus fermentum. Nunc pellentesque enim neque, ac scelerisque neque porttitor eget. Nullam efficitur varius euismod. Ut quis neque ut diam dapibus viverra. Aliquam at mollis eros, at convallis nisl. Etiam sed quam feugiat, luctus augue eu, eleifend felis. Aliquam interdum, nisl non ullamcorper hendrerit, sapien diam egestas dolor, eu ultrices eros massa eget ligula. Morbi eu sapien pulvinar, egestas lacus eget, maximus urna. Aenean eros risus, finibus et erat quis, efficitur mattis enim. Maecenas eget commodo risus, vitae pretium ipsum. Mauris bibendum eros sit amet orci fermentum, vitae accumsan mi aliquam. Interdum et malesuada fames ac ante ipsum primis in faucibus. Maecenas nec quam laoreet odio venenatis dictum id a nunc. Sed a tincidunt nulla, sed consectetur metus. Praesent viverra ipsum a neque consequat tempus. Maecenas sit amet dui lorem. Suspendisse interdum felis vel tortor euismod, ac malesuada ipsum posuere. Duis semper nisi vel malesuada suscipit. In convallis arcu eros, ut commodo odio tristique ut. Fusce finibus ex ut convallis varius. Cras sit amet iaculis ex, ut auctor dui. Morbi mollis urna eu felis sollicitudin mollis. Nam bibendum ex nisl, viverra rhoncus urna aliquam eget. Aenean sollicitudin gravida justo, sodales suscipit orci dictum vitae. Nam pretium lobortis nisl. Donec et eros consequat, imperdiet mi eget, auctor augue. Quisque condimentum, magna vitae pulvinar porta, magna lacus scelerisque dolor, vel pharetra mi tellus vel nisl. Sed malesuada eros vel nisi facilisis tempor. Aliquam convallis aliquet porttitor. Proin eu placerat orci, quis faucibus turpis. Donec sodales iaculis viverra. Pellentesque fringilla diam purus, in ullamcorper sem pulvinar eu. In ac dolor elementum, maximus orci nec, venenatis ex....

CSS

.high {
  background: linear-gradient(#bbb, white);
}

JavaScript

window.doScrolling = function(speed, duration) {
	var startingY = window.pageYOffset
  var elementY = speed
  // If element is close to page's bottom then window will scroll only to some position above the element.
  var targetY = document.body.scrollHeight - elementY < window.innerHeight ? document.body.scrollHeight - window.innerHeight : elementY
	var diff = targetY - startingY
  // Easing function: easeInOutCubic
  // From: https://gist.github.com/gre/1650294
  var easing = function (t) { return t<.5 ? 4*t*t*t : (t-1)*(2*t-2)*(2*t-2)+1 }
  var start

  if (!diff) return

	// Bootstrap our animation - it will get called right before next frame shall be rendered.
	window.requestAnimationFrame(function step(timestamp) {
    if (!start) start = timestamp
    // Elapsed miliseconds since start of scrolling.
    var time = timestamp - start
		// Get percent of completion in range [0, 1].
    var percent = Math.min(time / duration, 1)
    // Apply the easing.
    // It can cause bad-looking slow frames in browser performance tool, so be careful.
    percent = easing(percent)

    window.scrollTo(0, startingY + diff * percent)

		// Proceed with animation as long as we wanted it to.
    if (time < duration) {
      window.requestAnimationFrame(step)
    }
  })
}

// Apply event handlers. Example of firing the scrolling mechanism.
document.getElementById('scrollMid').addEventListener('click', doScrolling.bind(null, 500, 500))
document.getElementById('scrollTop').addEventListener('click', doScrolling.bind(null, 300, 500))
document.getElementById('scrollBot').addEventListener('click', doScrolling.bind(null, 20, 500))

// Or simply:
//doScrolling('#mytarget', 1000)