Adding Scroll To Top In WordPress Site

Imran Sayed
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

--

--

Imran Sayed

👤 Full Stack Developer at rtCamp, Speaker, Blogger, YouTuber, Wordpress, React, Node, Laravel Developer http://youtube.com/ImranSayedDev