Learn how to create a dynamic scroll-to-top button. It’ll slide in from the side of the page when you scroll down, so you can jump back to the top of the page. In fact, if you scroll down this page, you can see it in action!
How It Will Work
We’ll do most of this in CSS and with an off-screen <div>
element. We’ll give this div a CSS class called “scroll-to-top” so it can have a fixed position, and a high z-index (to make it always on top). Then we’ll use a bit of JavaScript to monitor the document scrolling. When the viewer scrolls down either 10% of the page height, or 300 pixels, we’ll add a second CSS class called “visible”. When the user scrolls back to the top, we’ll remove the “visible” class.
To make the scroll-to-top button show/hide smoothly, we’ll set transition:0.3s
in the scroll-to-top class, so the browser will animate the transitions for us.
Getting Started
importantYou need to be using a custom child theme on your WordPress website, because we’re going to edit functions.php.
We’ll start by creating some scaffold/placeholder files to hold our code and CSS, then we’ll connect it to our child theme’s functions.php and start filling it in.
In your custom child theme’s folder, create a subfolder called wpt-scroll-to-top. Go into this new folder and create two new empty files, called “scroll-to-top.css” and “scroll-to-top.js“. Leave them empty for now – we’ll paste some stuff into these later.
Back in your child theme’s main folder, create a new file called wpt-scroll-to-top.php – this is our main entry file. Paste the following into there to get started.
<?php // Block direct access. defined('WPINC') || die(); function wptsst_enqueue_scripts() { // We'll add some code in here soon... } add_action('wp_enqueue_scripts', 'wptsst_enqueue_scripts');
Next, open your child theme’s functions.php and paste the following into it to “include” our new code.
/** * WP Tutorials Scroll-to-top. */ require_once dirname(__FILE__) . '/wpt-scroll-to-top.php';
Save everything and reload a page on your website to check that everything is still working properly.
That’s a good starting point. We’ve got a PHP file (wpt-scroll-to-top.php) where we can put our WordPress code, and a couple of asset files to layout and control the frontend bits in the browser. Now we just need to fill-in the blanks (write the code).
The WordPress / PHP Bit
This tutorial doesn’t need much PHP. All we need to do is inject a bit of HTML into the document for our off-screen <div>
. We’ll do this by hooking wp_footer, so our <div>
will get rendered towards the end of the document. Because it’s got position:fixed
, we can actually inject our <div>
anywhere in the HTML, because it’s on-screen position is independent of all other elements, but I think it makes sense to put it in the footer – out of the way.
Open your custom child theme’s wpt-scroll-to-top.php file and paste the following into it.
<?php /** * WP Tutorials Scroll to Top (WPTSST) * * https://wp-tutorials.tech/refine-wordpress/dynamic-scroll-to-top-button/ */ // Block direct access. defined('WPINC') || die(); function wptsst_enqueue_scripts() { $theme_version = wp_get_theme()->get('Version'); $base_url = get_stylesheet_directory_uri() . '/' . pathinfo(__FILE__, PATHINFO_FILENAME) . '/'; wp_enqueue_style('scroll-to-top', $base_url . 'scroll-to-top.css', null, $theme_version); wp_enqueue_script('scroll-to-top', $base_url . 'scroll-to-top.js', null, $theme_version, true); } add_action('wp_enqueue_scripts', 'wptsst_enqueue_scripts'); function wptsst_insert_offscreen_div() { echo '<div class="scroll-to-top">'; echo '<div class="stt-inner">'; // Uncomment/edit which ever of these you want to use for your scroll-top-top icon. // Your own image... // echo '<img src="your-image-url.png" alt="Scroll to top" />'; // Font Awesome 4... // echo '<i class="fa fa-hand-o-up" aria-hidden="true"></i>'; // Font Awesome 5... echo '<i class="fas fa-hand-point-up"></i>'; echo '</div>'; // .stt-inner echo '</div>'; // .scroll-to-top } add_action('wp_footer', 'wptsst_insert_offscreen_div');
Notice that the actual HTML we put inside our scroll-to-top <div>
will depend on how you want it to look on your site. Here, we’re using FontAwesome5 to render a hand pointing upwards. If your site doesn’t have FontAwesome then you can either add it, or use an image… or whatever you want.
Add the Styles
Open scroll-to-top.css (in the wpt-scroll-to-top folder) and paste the following into it, to get you started.
/* * WP Tutorials : Scroll to Top. */ .scroll-to-top { font-size: 20pt; width: 2.5em; height: 2.5em; position: fixed; right: -2.5em; bottom: 4em; z-index: 1000; opacity: 0.0; transition: 0.5s; } .scroll-to-top.visible { right: 1rem; opacity: 1.0; } .scroll-to-top .stt-inner { background-image: linear-gradient(128deg, #0693e3 0, #9b51e0 100%); border: 4px solid black; width: 100%; height: 100%; border-radius: 50%; cursor: pointer; transition: 0.3s; } .scroll-to-top .stt-inner:hover { text-shadow: 0 0 0.5em rgba( 255, 255, 255, 0.75 ); } .scroll-to-top .stt-inner i, .scroll-to-top .stt-inner img { color: white; position: absolute; left: 50%; top: 50%; transform: translate(-50%, -50%); }
Notice how we set cursor:pointer
on the stt-inner class to make it look like a button when the user hovers their mouse over it.
Tie it Together with JavaScript
If you reload your site right now, you’ll see that nothing new happens. That’s because the scroll-to-top <div>
is always off-screen. We need to add some JavaScript to listen for the document’s scroll event, then decide when we need to add or remove the “visible” class to the scroll-to-top <div>
. Open scroll-to-top.js in the wpt-scroll-to-top folder, and paste the following into it.
/** * WP Tutorials scroll-to-top * * https://wp-tutorials.tech/refine-wordpress/dynamic-scroll-to-top-button/ */ document.addEventListener('DOMContentLoaded', function() { 'use strict'; const scrollPercentageThreshold = 0.10; const scrollPixelThreshold = 300; // Diagnostics to show that our script has loaded correctly. // console.log('scroll-to-top : load'); var scrollToTopContainer = document.querySelector('.scroll-to-top'); var scrollToTopInner = null; if (scrollToTopContainer) { scrollToTopInner = scrollToTopContainer.querySelector('.stt-inner'); } if (scrollToTopInner) { scrollToTopInner.addEventListener("click", function() { window.scrollTo(0, 0); }); document.addEventListener('scroll', function(e) { var offset = window.scrollY; var total = document.body.scrollHeight; // Uncomment this to see the current scroll metrics. // console.log( `${window.scrollY} / ${document.body.scrollHeight}` ); var isVisible = false; if ((1.0 * offset / total) > scrollPercentageThreshold) { isVisible = true; } else if (offset > scrollPixelThreshold) { isVisible = true; } else { // ... } if (isVisible && !scrollToTopContainer.classList.contains('visible')) { scrollToTopContainer.classList.add('visible'); } else if (!isVisible && scrollToTopContainer.classList.contains('visible')) { scrollToTopContainer.classList.remove('visible'); } else { // No change } }); } });
The logic works like this:
- Wait until the document has raised the DOMContentLoaded event, so we’re know that everything is ready-to-go.
- Find the first instance of an element with the scroll-to-top class.
- Within our scroll-to-top-element, find the first instance of an element with the stt-inner class – this is our fake clickable “button”.
- If we’ve found an stt-inner
<div>
…- Add a click event handler to the stt-inner
<div>
. - When the document raises the scroll event…
- Add/remove “visible” to the scroll-to-top element’s class list, based on the document’s current vertical scroll position.
- Add a click event handler to the stt-inner
Deploy & Test
Save everything, reload some content on your site and have a play with it.
- Try removing transition:0.3s from the scroll-to-top class in scroll-to-top.css.
- Tinker with the JavaScript to adjust the threshold for when we add/remove the visible class to the scroll-to-top <div>.
Happy scrolling! 😎👍