UPD: I've created an npm package that works better than the following solution and easier to use.
My smoothScroll function
I've taken the wonderful solution of Steve Banton and wrote a function that makes it more convenient to use. It'd be easier just to use window.scroll()
or even window.scrollBy()
, as I've tried before, but these two have some problems:
- Everything becomes junky after using them with a smooth behavior on.
- You can't prevent them anyhow and have to wait till the and of the scroll.
So I hope my function will be useful for you. Also, there is a lightweight polyfill that makes it work in Safari and even IE.
Here is the code
Just copy it and mess up with it how ever you want.
import smoothscroll from 'smoothscroll-polyfill';
smoothscroll.polyfill();
const prepareSmoothScroll = linkEl => {
const EXTRA_OFFSET = 0;
const destinationEl = document.getElementById(linkEl.dataset.smoothScrollTo);
const blockOption = linkEl.dataset.smoothScrollBlock || 'start';
if ((blockOption === 'start' || blockOption === 'end') && EXTRA_OFFSET) {
const anchorEl = document.createElement('div');
destinationEl.setAttribute('style', 'position: relative;');
anchorEl.setAttribute('style', `position: absolute; top: -${EXTRA_OFFSET}px; left: 0;`);
destinationEl.appendChild(anchorEl);
linkEl.addEventListener('click', () => {
anchorEl.scrollIntoView({
block: blockOption,
behavior: 'smooth',
});
});
}
if (blockOption === 'center' || !EXTRA_OFFSET) {
linkEl.addEventListener('click', () => {
destinationEl.scrollIntoView({
block: blockOption,
behavior: 'smooth',
});
});
}
};
export const activateSmoothScroll = () => {
const linkEls = [...document.querySelectorAll('[data-smooth-scroll-to]')];
linkEls.forEach(linkEl => prepareSmoothScroll(linkEl));
};
To make a link element just add the following data attribute:
data-smooth-scroll-to="element-id"
Also you can set another attribute as an addtion
data-smooth-scroll-block="center"
It represents the block
option of the scrollIntoView()
function. By default, it's start
. Read more on MDN.
Finally
Adjust the smoothScroll function to your needs.
For example, if you have some fixed header (or I call it with the word masthead
) you can do something like this:
const mastheadEl = document.querySelector(someMastheadSelector);
// and add it's height to the EXTRA_OFFSET variable
const EXTRA_OFFSET = mastheadEl.offsetHeight - 3;
If you don't have such a case, then just delete it, why not :-D.
scrollIntoView
is troubling.scroll-margin
andscroll-padding
.