Scroll an Element Into View with CSS or Vanilla JavaScript
Scrolling to an anchor element can be done with CSS alone by adding:
html {
scroll-behavior: smooth;
}
If the site has a fixed or sticky header, it can be accounted for by setting the scroll-padding-top
:
html {
scroll-behavior: smooth;
scroll-padding-top: 100px;
}
header {
height: 100px;
position: sticky;
top: 0;
}
For more control, to use a calculation of the height of the header to offset by for example, or to tie an event listener to something that isn't an <a>
element, the smooth scroll can be managed with VanillaJS.
In this example, a click on the HTML element with the ID myButton
will trigger a smooth scroll to the element with the ID myDestination
using the JavaScript function Element: scrollIntoView()
:
document.addEventListener('DOMContentLoaded', function () {
document.querySelector('#myButton').addEventListener('click', function (event) {
event.preventDefault();
this.blur();
const myDestination = document.querySelector('#myDestination');
myDestination.scrollIntoView({'behavior': 'smooth'});
});
});
If the site has a fixed header, scrollIntoView()
will not work exactly as intended. It doesn't account for the header. Get the Y coordinate of the top of the object to scroll into view using offsetTop
and subtract the height of the fixed header element from that. Scroll the window to the Y position, rather than the element directly:
document.addEventListener('DOMContentLoaded', function () {
document.querySelector('#myButton').addEventListener('click', function (event) {
event.preventDefault();
this.blur();
const myDestination = document.querySelector('#myDestination');
const headerHeight = document.querySelector('header').offsetHeight;
const topOfMyDestination = myDestination.offsetTop - headerHeight;
window.scroll({ top: topOfMyDestination, behavior: "smooth" });
});
});
Another variation would be to tie an event listener to all anchor links and scroll them into view using JavaScript. This can be used, for example, to keep the hash out of the URL and the browser history, allowing the back button to navigate back to the previous page instead of the previous anchor. This example also accommodates a header that is position: fixed
at the top of the page:
function handleJumpLinks() {
document.querySelectorAll( 'a[href^="#"]' ).forEach( ( a ) => {
a.addEventListener( 'click', function ( event ) {
event.preventDefault();
this.blur();
const target = document.querySelector( this.getAttribute( 'href' ) );
if ( target ) {
const headerHeight = document.querySelector('header').offsetHeight;
const topOfMyDestination = target.offsetTop - headerHeight;
window.scroll({ top: topOfMyDestination, behavior: "smooth" });
}
} );
} );
}
if ( document.readyState === 'loading' ) {
// Loading hasn't finished yet, set an event listener
document.addEventListener( 'DOMContentLoaded', handleJumpLinks );
} else {
// `DOMContentLoaded` has already fired, run the func directly
handleJumpLinks();
}
Feedback?
Email us at enquiries@kinsa.cc.