I implemented a sophisticated scrolling function inspired by the insights shared by @SachinShah above to cater to my specific requirements.
This could be beneficial for someone else facing similar needs.
Before delving into its functionality, let me outline what it accomplishes:
- It smoothly scrolls to a designated element's id
- Follows a specified duration seamlessly
- Offers an option to adjust the target offset, particularly useful when dealing with sticky/smart headers
- Allows control over the smoothness of the scroll using setInterval function
Please bear in mind that:
- The method utilizes the relative scrolling approach
window.scrollBy
, necessitating the determination of scrollDirection (up/down) within the logic
- Both scrollDuration and scrollSmoothness are measured in milliseconds
/**
* Scroll to the top of the page in a specified duration(ms) and smoothness(ms)
* ref: https://stackoverflow.com/a/52478645/3556531
* @param {String} elementID
* @param {Int} scrollDuration
* @param {Int} offset
* @param {Int} scrollSmoothness
*/
const fancyAScroll = (
elementID = 'main-content',
scrollDuration = 500,
offset = 0, // I had to use 120 to compensate for a sticky header
scrollSmoothness = 10
) => {
const accuracyBuffer = 10
try {
// #1 Calculate the final offset position to scroll-to
const element = document?.getElementById(elementID)
const bodyRect = document?.body?.getBoundingClientRect().top
const elementRect = element?.getBoundingClientRect().top
const elementPosition = elementRect - bodyRect
const offsetPosition = elementPosition - offset // final - target position to scroll
// #2 calculate steps & direction (up or down)
const scrollStepUnit = offsetPosition / (scrollDuration / scrollSmoothness)
const scrollStepDirection = offsetPosition > window?.scrollY ? '' : '-'
const scrollStepY = `${scrollStepDirection}${scrollStepUnit}`
// #3 keep on relatively scrolling untill reached to the destination
const scrollInterval = setInterval(() => {
let targetRangeReached =
offsetPosition - accuracyBuffer < window.scrollY &&
window.scrollY < offsetPosition + accuracyBuffer
targetRangeReached ? clearInterval(scrollInterval) : window.scrollBy(0, scrollStepY)
}, scrollSmoothness)
}
catch (error) {
console.error('Error @scrollTopWithDuration\n', error)
}
}
export default fancyAScroll