Skip to content

Instantly share code, notes, and snippets.

@Kernix13
Last active April 6, 2024 16:18
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save Kernix13/cf24e4390c72c0dc0e5ccb30c277d843 to your computer and use it in GitHub Desktop.
Save Kernix13/cf24e4390c72c0dc0e5ccb30c277d843 to your computer and use it in GitHub Desktop.
Back To Top Button
<!-- Simpler version on my portfolio site:
https://jameskernicky.netlify.app/
https://github.com/Kernix13/personal-portfolio
-->
<button id="back-to-top-btn"><i class="fa-solid fa-angle-up"></i></button>
<!-- Bootstrap icon instead of font awesome -->
<svg
xmlns="http://www.w3.org/2000/svg"
width="16"
height="16"
fill="currentColor"
class="bi bi-chevron-up"
viewBox="0 0 16 16"
>
<path
fill-rule="evenodd"
d="M7.646 4.646a.5.5 0 0 1 .708 0l6 6a.5.5 0 0 1-.708.708L8 5.707l-5.646 5.647a.5.5 0 0 1-.708-.708z"
/>
</svg>
const backToTopButton = document.querySelector('#back-to-top-btn');
window.addEventListener('scroll', scrollFunction);
/**
* Display or hide back-to-top btn based on scrollY
*/
function scrollFunction() {
if (window.scrollY > 300) {
// Show backToTopButton
if (!backToTopButton.classList.contains('btnEntrance')) {
backToTopButton.classList.remove('btnExit');
backToTopButton.classList.add('btnEntrance');
backToTopButton.style.display = 'block';
}
} else {
// Hide backToTopButton
if (backToTopButton.classList.contains('btnEntrance')) {
backToTopButton.classList.remove('btnEntrance');
backToTopButton.classList.add('btnExit');
setTimeout(function () {
backToTopButton.style.display = 'none';
}, 125);
}
}
}
backToTopButton.addEventListener('click', smoothScrollBackToTop);
/**
* Control scroll animation
*/
function smoothScrollBackToTop() {
const duration = 1250;
let start = null;
const startPosition = window.scrollY;
const distanceToTop = -1 * startPosition;
window.requestAnimationFrame(step);
/**
* Synchronize animation using timestamp
* @param {milliseconds} timestamp
*/
function step(timestamp) {
if (!start) start = timestamp;
const progress = timestamp - start;
window.scrollTo(
0,
easeInOutCubic(progress, startPosition, distanceToTop, duration)
);
if (progress < duration) window.requestAnimationFrame(step);
}
}
/**
*
* Cubic-bezier function for scroll animation
*
* @param {milliseconds} prog
* @param {pixels} startPos
* @param {pixels} dist
* @param {milliseconds} dur
* @returns
*/
function easeInOutCubic(prog, startPos, dist, dur) {
prog /= dur / 2;
if (prog < 1) {
return (dist / 2) * prog * prog * prog + startPos;
}
prog -= 2;
return (dist / 2) * (prog * prog * prog + 2) + startPos;
}
.fa-solid {
font-size: 2rem;
padding-bottom: 0.5em;
}
.fa-angle-up {
color: #fff;
}
#back-to-top-btn {
display: none;
position: fixed;
font-size: 18px;
width: 44px;
height: 44px;
bottom: 10px;
left: 10px;
font-weight: bolder;
border: none;
outline: none;
background-color: rgba(0, 0, 0, 0.4);
color: white;
cursor: pointer;
padding: 0.25em 0.5em;
border-radius: 0.25em;
transition-duration: 100ms;
transition-timing-function: ease-in-out;
transition-property: background-color, color;
z-index: 999;
}
#back-to-top-btn:hover,
#back-to-top-btn:focus {
background-color: rgba(0, 0, 0, 0.8);
color: #fff;
}
/* Animations */
.btnEntrance {
animation-duration: 0.5s;
animation-fill-mode: both;
animation-name: btnEntrance;
}
/* fadeInUp */
@keyframes btnEntrance {
from {
opacity: 0;
transform: translate3d(0, 100%, 0);
}
to {
opacity: 1;
transform: translate3d(0, 0, 0);
}
}
.btnExit {
animation-duration: 0.25s;
animation-fill-mode: both;
animation-name: btnExit;
}
/* fadeOutDown */
@keyframes btnExit {
from {
opacity: 1;
}
to {
opacity: 0;
transform: translate3d(0, 100%, 0);
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment