Adding Scroll To Top In WordPress Site
5 min readDec 22, 2021
In this blog, we will learn about how to add a scroll to the top button in WordPress Site.
Scroll To Top Button
Add the scroll to top button in footer.php
Note that some of the classes I am using are from tailwindcss
<div id="footer-wrapper" class=" text-white footer-wrapper">
<footer id="colophon" class="site-footerpt-50px pb-43px lg:pt-85px lg:pb-74px">
<div class="back-to-top">
<button id="back-to-top">
<svg class="w-6 h-6 transform -rotate-90" id="icon-arrow-heavy" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path d="M13 7v-6l11 11-11 11v-6h-13v-10z"/>
</svg>
<span><?php esc_html_e( 'go to top', 'text-domain' ); ?></span>
</button>
</div>
</div><!-- #footer-wrapper -->
<?php
wp_footer();
?>
</body>
</html>
InViewPortAnimation
Create a JS file called in-viewport-animation.js
.
$ = jQuery;
$.fn.extend( {
getPath: function () {
let path, node = this;
while ( node.length ) {
var realNode = node[0], name = realNode.nodeName;
if ( ! name ) {
break;
}
name = name.toLowerCase();
let parent = node.parent();
let sameTagSiblings = parent.children( name );
if ( sameTagSiblings.length ) {
let allSiblings = parent.children();
let index = allSiblings.index( realNode ) + 1;
if ( index > 1 ) {
name += ':nth-child(' + index + ')';
}
}
path = name + ( path ? '>' + path : '' );
node = parent;
}
return path;
}
} );
/**
* Used to attach to a element to always watch if its in the viewport.
*
* When scrolling, if element is in viewport add a parameter, a data attribute and a class name.
*/
export class InViewportAnimation {
_elements;
constructor() {
this.boundScrollEvent = false;
this.elements = {};
this.selectors = '';
const that = this;
that.selectors = selectors;
that.scroll();
that.checkElements();
that.toggleClasses();
}
addElement( element ) {
if ( $( element ).length ) {
if ( 'undefined' !== typeof this.elements[ $( element ).getPath() ] ) {
return;
}
$( element ).toggleClass( 'initiate-scroll-animation', true );
this.elements[ $( element ).getPath() ] = element;
}
}
setClasses( elem ) {
const inViewport = this.inViewport( elem );
elem.inViewport = inViewport;
elem.attr( 'data-in-viewport', inViewport ).toggleClass( 'in-viewport', inViewport );
this.setInlineClasses( inViewport, elem );
}
setInlineClasses( inViewport, elem ) {
if ( ! inViewport ) {
elem.css( { opacity: '0.5', transform: 'translateY(15px)', transition: '1s transform ease, 1s opacity ease' } );
} else {
elem.css( { opacity: '1', transform: 'translateY(0)', transition: '1s transform ease, 1s opacity ease' } );
}
}
checkElements() {
$( this.selectors ).each( ( i, elem ) => {
this.addElement( elem );
} );
}
scroll() {
if ( ! this.boundScrollEvent ) {
$( window ).on( 'scroll', () => {
this.checkElements();
this.toggleClasses();
} );
this.boundScrollEvent = true;
}
}
toggleClasses( elem = false ) {
if ( ! elem ) {
if ( ! Object.keys( this.elements ).length ) {
return;
}
Object.keys( this.elements ).forEach( ( path ) => {
if ( 'skip' === this.elements[ path ] ) {
return;
}
const elem = $( this.elements[ path ] );
const inViewport = this.inViewport( elem );
elem.inViewport = inViewport;
elem.attr( 'data-in-viewport', inViewport ).toggleClass( 'in-viewport', inViewport );
this.setInlineClasses( inViewport, elem );
if ( inViewport ) {
this.elements[ path ] = 'skip';
}
} );
} else {
const inViewport = this.inViewport( elem );
elem.inViewport = inViewport;
elem.attr( 'data-in-viewport', inViewport ).toggleClass( 'in-viewport', inViewport );
this.setInlineClasses( inViewport, elem );
}
}
inViewport( elem ) {
return this.elementBottom( elem ) > this.viewportTop() && this.elementTop( elem ) < this.viewportBottom();
}
elementBottom( elem ) {
return this.elementTop( elem ) + $( elem ).outerHeight();
}
viewportTop() {
return $( window ).scrollTop();
}
elementTop( elem ) {
return $( elem ).offset().top;
}
viewportBottom() {
return this.viewportTop() + $( window ).height();
}
}
Debounce function
Create a JS file called functions.js
/**
* Calls the given function after the given interval.
*
* @param {Object} func Function name.
* @param {number} wait Time in milliseconds.
*
* @return {Function} Debounced function.
*/
export const debounce = ( func, wait ) => {
let timeout;
/**
* Debounce function.
*/
return function() {
const context = this,
args = arguments;
/**
* Later function.
*/
const later = function() {
timeout = null;
func.apply( context, args );
};
clearTimeout( timeout );
timeout = setTimeout( later, wait );
};
};
Scroll To Top Main JS file
Create another file called scroll-to-top.js
/**
* Back to Top.
*
* @package WPR
*/
import { debounce } from "./functions";
import { InViewportAnimation } from './in-viewport-animation';
( function ( $ ) {
class BackToTop {
/**
* Constructor.
*
* @return {void}
*/
constructor() {
this.backToTopEl = $( '#back-to-top' );
this.siteFooter = $( 'footer#colophon.site-footer' );
this.window = $( window );
// The window scroll position after which we show the scroll to top button.
this.scrollOffset = 200;
if ( ! this.backToTopEl ) {
return;
}
this.addEvents();
}
addEvents() {
this.backToTopEl.on( 'click', this.scrollWindowToTop );
this.window.on( 'scroll', () => debounce( this.toggleScrollToTopBtnVisibilty(), 1000 ) );
new InViewportAnimation();
}
/**
* Toggle scroll button visibility.
*
* When the scroll position is large than scrollOffset
* we will show the scroll to top button,
* else hide it.
*
* @return {void}
*/
toggleScrollToTopBtnVisibilty() {
// If the scroll position is larger than scrollOffset.
if ( window.scrollY > this.scrollOffset ) {
this.backToTopEl.addClass( 'is-visible' );
const top_of_element = this.siteFooter.offset().top;
const bottom_of_element = this.siteFooter.offset().top + this.siteFooter.outerHeight();
const bottom_of_screen = $( window ).scrollTop() + $( window ).innerHeight();
const top_of_screen = $( window ).scrollTop();
if ( ( bottom_of_screen > top_of_element ) && ( top_of_screen < bottom_of_element ) ) {
const diff = bottom_of_screen - top_of_element;
this.backToTopEl.parent( '.back-to-top' ).css( 'bottom', ( 20 + diff ) + 'px' );
} else {
this.backToTopEl.parent( '.back-to-top' ).css( 'bottom', '20px' );
}
} else {
this.backToTopEl.removeClass( 'is-visible' );
}
}
/**
* Scroll window to top.
*
* When the back to top button is clicked scroll to top position.
* @return {void}
*/
scrollWindowToTop() {
window.scrollTo( {
top: 0,
behavior: 'smooth'
} );
}
}
new BackToTop();
} )( jQuery );
Scroll To Top CSS
.back-to-top {
display: none;
@screen lg {
position: fixed;
bottom: 20px;
right: 0;
align-items: center;
margin: auto;
height: 140px;
width: 100px;
justify-content: center;
z-index: 3;
display: flex;
}
button {
display: flex;
flex-direction: column;
align-items: center;
color: #d5d7d8;
cursor: pointer;
font-style: normal;
font-weight: 400;
font-size: 12px;
line-height: 137.74%;
border-color: transparent;
background-color: transparent;
opacity: 0;
-ms-user-select: none;
user-select: none;
-moz-user-select: none;
-khtml-user-select: none;
-webkit-user-select: none;
-o-user-select: none;
transition: all .5s ease;
transition: color 0ms;
&.is-visible {
opacity: 1;
animation: fadein 1s;
-moz-animation: fadein 1s;
-webkit-animation: fadein 1s;
-o-animation: fadein 1s;
}
svg {
filter: brightness(0) saturate(100%) invert(100%) sepia(1%) saturate(1993%) hue-rotate(169deg) brightness(99%) contrast(70%);
}
&:hover {
color: grey;
background-color: transparent;
svg {
filter: brightness(0) saturate(100%) invert(46%) sepia(9%) saturate(10%) hue-rotate(328deg) brightness(92%) contrast(85%);
}
}
}
}
That’s all folks