Skip to content

Instantly share code, notes, and snippets.

@firestar300
Last active May 6, 2020 14:23
Show Gist options
  • Save firestar300/a768ed3bb120d34b9ad0c3f077b449c9 to your computer and use it in GitHub Desktop.
Save firestar300/a768ed3bb120d34b9ad0c3f077b449c9 to your computer and use it in GitHub Desktop.
smoothScroll.js
/**
* Scroll to animation
* @param {(HTMLElement|Number)} destination Scroll to an specific element or a numerical value
* @param {Number} duration Duration of the animation
* @param {String} easing Easing of the animation
* @param {Number} offset Offset of the scroll
* @param {Function} callback Callback function
*/
const smoothScroll = (destination, duration = 300, easing = 'linear', offset = 0, callback) => {
const easings = {
linear(t) {
return t
},
easeInQuad(t) {
return t * t
},
easeOutQuad(t) {
return t * (2 - t)
},
easeInOutQuad(t) {
return t < 0.5 ? 2 * t * t : -1 + (4 - 2 * t) * t
},
easeInCubic(t) {
return t * t * t
},
easeOutCubic(t) {
return --t * t * t + 1
},
easeInOutCubic(t) {
return t < 0.5 ? 4 * t * t * t : (t - 1) * (2 * t - 2) * (2 * t - 2) + 1
},
easeInQuart(t) {
return t * t * t * t
},
easeOutQuart(t) {
return 1 - --t * t * t * t
},
easeInOutQuart(t) {
return t < 0.5 ? 8 * t * t * t * t : 1 - 8 * --t * t * t * t
},
easeInQuint(t) {
return t * t * t * t * t
},
easeOutQuint(t) {
return 1 + --t * t * t * t * t
},
easeInOutQuint(t) {
return t < 0.5 ? 16 * t * t * t * t * t : 1 + 16 * --t * t * t * t * t
},
}
const start = window.pageYOffset
// eslint-disable-next-line no-undef
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 - offset
: destination.getBoundingClientRect().top - document.body.getBoundingClientRect().top - offset
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() {
// eslint-disable-next-line no-undef
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
}
window.requestAnimationFrame(scroll)
}
scroll()
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment