Smooth Scroll “Back to Top” Button
I have been repeatedly asked in the comments to explain how the "Back to Top" arrow is implemented on this site. I'm sharing it now.
Some advantages:
- Works in all browsers;
- Disappears at the top of the screen;
- Can be added to any website, not just WordPress.
We will get a fixed-position button that, when clicked, smoothly scrolls the screen to the top and the arrow disappears at the top.
Below are two options: using pure JS and using jQuery. The button code is suitable for any engine, not just WordPress - it could be Drupal, Bitrix, Joomla, DLE, or UCOZ.
Option 1: Native JS
document.addEventListener( 'DOMContentLoaded', function(){ let div = document.createElement( 'div' ) div.innerHTML = `<button role="button" aria-label="Scroll Top" class="scroll-top-btn"></button>`.trim() let scrollTop = div.firstChild document.body.append( scrollTop ) scrollTop.addEventListener( 'click', ev => { window.scrollTo( 0, 0 ) } ) let showHideButton = function(){ window.scrollY > 300 ? scrollTop.classList.add( '--visible' ) : scrollTop.classList.remove( '--visible' ) } window.addEventListener( 'scroll', showHideButton ) showHideButton() } );
Smooth scrolling is achieved with the following styles:
html{ scroll-behavior: smooth; scroll-padding-top: calc( var(--header-height) + 1rem ); }
SCSS Styles
// scroll-top --- .scroll-top-btn{ font-size: 150%; // button size padding:0; border:0; // reset button display: block; overflow: hidden; width: 0; height: 0; z-index: 99; position: fixed; bottom: 2rem; right: 2rem; line-height: 0; border-radius: var(--border-radius); box-shadow: 0 3px 30px -5px rgb(0 0 0 / 30%); background-color: var(--white); background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 20 20' fill='%23999' aria-hidden='true'%3E%3Cpath fill-rule='evenodd' d='M14.707 12.707a1 1 0 01-1.414 0L10 9.414l-3.293 3.293a1 1 0 01-1.414-1.414l4-4a1 1 0 011.414 0l4 4a1 1 0 010 1.414z' clip-rule='evenodd'%3E%3C/path%3E%3C/svg%3E"); background-repeat: no-repeat; background-size: 70%; background-position: center 50%; opacity: .6; transition: all 150ms; cursor:pointer; @include layoutBreak { display: none; } &.--visible { overflow: visible; width: 2em; height: 2em; } &:hover{ opacity: 1; } }
Option 1.2: Native JS (with smooth scroll function)
document.addEventListener( 'DOMContentLoaded', function(){ // create DOM element const scrollTopHTML = `<button role="button" area-lable="Scroll Top" class="scroll-top-btn"></button>` const div = document.createElement( 'div' ) div.innerHTML = scrollTopHTML.trim() const scrollTop = div.firstChild document.body.append( scrollTop ) // init scrollTop.addEventListener( 'click', button_click ) window.addEventListener( 'scroll', showHideButton ) showHideButton() // methods function button_click( ev ) { ev.preventDefault(); scroll_to( { element: document.documentElement, goto: 0, speed: 2000, frames: 10, easing_func: 'easeOutCirc', } ) } function showHideButton() { window.scrollY > 300 ? scrollTop.classList.add( '--visible' ) : scrollTop.classList.remove( '--visible' ) } function scroll_to( args ) { /** * t = Time - Amount of time that has passed since the beginning of the animation. * Usually starts at 0 and is slowly increased using a game loop or other update function. * b = Beginning value - The starting point of the animation. * Usually it's a static value, you can start at 0 for example. * c = Change in value - The amount of change needed to go from starting point to end point. * It's also usually a static value. * d = Duration - Amount of time the animation will take. * Usually a static value aswell. * * @see https://spicyyoghurt.com/tools/easing-functions * @see https://easings.net/ */ const easing_funcs = { easeLinear: ( t, b, c, d ) => { return c * t / d + b }, easeInSine: ( t, b, c, d ) => { return -c * Math.cos(t / d * (Math.PI / 2)) + c + b; }, easeOutSine: ( t, b, c, d ) => { return c * Math.sin(t / d * (Math.PI / 2)) + b; }, easeInCubic: ( t, b, c, d ) => { return c * (t /= d) * t * t + b; }, easeOutCubic: ( t, b, c, d ) => { return -c * (t /= d) * (t - 2) + b }, easeInExpo: ( t, b, c, d ) => { return (t === 0) ? b : c * Math.pow(2, 10 * (t / d - 1)) + b; }, easeOutExpo: ( t, b, c, d ) => { return ( t === d ) ? b + c : c * ( -Math.pow( 2, -10 * t / d ) + 1 ) + b }, easeOutCirc: ( t, b, c, d ) => { return c * Math.sqrt(1 - (t = t / d - 1) * t) + b }, } const el = args.element || document.documentElement const speed = args.speed const frames = args.frames || 10 const goto_pos = args.goto const easing_func = args.easing_func || 'easeLinear' const anim_end_func = args.anim_end || null const anim_start_func = args.anim_start || null const start_pos = el.scrollTop const start_time = Date.now() let tuntime_frames = Math.round( speed / frames ) const recursive = () => { let left_time = ( Date.now() - start_time ) let anim_tick = left_time / tuntime_frames-- let anim_step = Math.min( left_time / speed, 1 ) // max 1 el.scrollTop = easing_funcs[ easing_func ]( anim_step, start_pos, (goto_pos - start_pos), 1 ) if( anim_step !== 1 ){ // next anim step this._scroll_to_tick_tm = setTimeout( recursive, anim_tick ) } // done else { delete this._scroll_to_tick_tm // add a delay for sure anim_end_func ? setTimeout( anim_end_func, 20 ) : null } } // RUN if already not in process if( ! this._scroll_to_tick_tm ){ anim_start_func && anim_start_func() recursive() } } } );
Use the button styles from example 1.
Option 2: "Back to Top" Button in Pure JavaScript
View DEMO in pure javascript >>>
If jQuery is not present on the site, there is no need to include a fairly large framework just to install such a button.
To implement a smoothly scrolling "back to top" button without jQuery, use the following js code:
The CSS styles should be specified separately in the style file:
.scrollTop{ background:url('path_to_file.png') 0 0 no-repeat; width:50px; height:70px; bottom:10px; left:48%; } .scrollTop:hover{ background-position:0 -76px; }
Option 3: "Back to Top" Buttons in jQuery
1. Connect jQuery
First, we need to connect jQuery, if it is not already installed on your site (this rarely happens). To do this, copy the following code into the theme file functions.php:
add_action('wp_enqueue_scripts', 'my_scripts_method' ); function my_scripts_method(){ wp_enqueue_script( 'jquery' ); }
If you already have jQuery connected, you can skip this step.
2. Embed the .js code
The next step is to embed the code for the button itself. To do this, create a file my_topbutton.js and insert the following code into it. Then you need to connect this file to the page.
Alternatively, to avoid dealing with a file, you can simply copy this code into an existing .js file.
This code should be connected after the jQuery library code.
jQuery(document).ready(function($){ /** * jQuery Back to Top Button. * Author: Timur Kamaev - wp-kama.ru * version 2.2 */ $('body').append('<style>\ .scrollTop{\ display:none; z-index:9999; position:fixed; bottom:10px; left:48%; width:50px; height:70px;\ background:url(http://example.com/path_to_file.png) 0 0 no-repeat;\ }\ .scrollTop:hover{ background-position:0 -76px;}\ </style>'); var speed = 500, $scrollTop = $('<a href="#" class="scrollTop"></a>').appendTo('body'); $scrollTop.click(function(e){ e.preventDefault(); $( 'html:not(:animated),body:not(:animated)' ).animate({ scrollTop: 0}, speed ); }); // appearance function show_scrollTop(){ ( $(window).scrollTop() > 300 ) ? $scrollTop.stop().fadeIn(600) : $scrollTop.stop().fadeOut(600); } $(window).scroll( function(){ show_scrollTop(); } ); show_scrollTop(); });
3. Adjust CSS styles
In the embedded JS code, there are lines with CSS styles:
$('body').append('<style>\ .scrollTop{\ display:none; z-index:9999; position:fixed; bottom:10px; left:48%; width:50px; height:70px;\ background:url(http://example.com/path_to_file.png) 0 0 no-repeat;\ }\ .scrollTop:hover{ background-position:0 -76px;}\ </style>');
Instead of http://example.com/path_to_file.png
, you need to specify the path to the image file with the arrow image. The image needs to be uploaded to the site.
You also need to adjust the sizes for the image: width:50px; height:70px;
and background-position:0 -76px;
. These sizes are calculated for an image of 50x140 pixels:
If you have a different image, in the parameter width:50px;
specify the width of the image; in the parameter height:70px;
specify half the height (the height of the top part of the image); in the parameter background-position:0 -76px;
- how many pixels to move from the top of the image when hovering over the "button". For this image, it's -76px.
That's it, all set!
So, in three steps, you can install the "back to top" button, which, when clicked, will smoothly scroll the user back to the top of the page.
#3.2 CSS styles without using an image - even simpler!
Due to the latest trends in simplicity, you can completely avoid using an image and simply style the button using CSS styles, here's an example:
$('body').append('<style>\ .scrollTop{\ display:none; z-index:9999; position:fixed; bottom:0; padding:1em 2em; left:48%; border-radius:.2em;\ background:rgba(0,0,0,0.2); color:#fff;\ }\ .scrollTop:hover{ background:rgba(0,0,0,0.6); color:#fff; text-decoration:none; }\ .scrollTop:before{ content:"▴"; /* ▲ ▴ △ ▵ ⏫ ⏶ ⧋ */ }\ </style>');
Replace the similar lines in the script code with these, and you will get a button like this:
Images for Buttons (for options 2 and 3)
I gathered several images that you might like.
Copy the image to your site and then adjust the CSS styles for the copied image, like this:
.scrollTop{ background:url('path_to_file.png') 0 0 no-repeat; width:50px; /* adjust: image width */ height:70px; /* adjust: button height - half of the image height */ bottom:10px; left:48%; } .scrollTop:hover{ /* adjust: offset on hover, needs to be adjusted manually. Approximately equal to the button height */ background-position:0 -76px; }