Smart Smooth scroll-to-top button that can be dragged to reposition and auto-hide
// ==UserScript==
// @name Smart Scroll to Top Button
// @namespace U2Nyb2xsIHRvIFRvcCBCdXR0b24
// @version 1.0
// @description Smart Smooth scroll-to-top button that can be dragged to reposition and auto-hide
// @author smed79
// @license GPLv3
// @icon https://i25.servimg.com/u/f25/11/94/21/24/scroll10.png
// @run-at document-end
// @match https://*/*
// @grant none
// ==/UserScript==
(function() {
'use strict';
// Create the button element
const button = document.createElement('div');
button.id = 'scroll-to-top-btn';
button.innerHTML = '↑';
// Style the button
const style = document.createElement('style');
style.textContent = `
#scroll-to-top-btn {
position: fixed;
bottom: 25px;
right: 25px;
width: 48px;
height: 48px;
border-radius: 50%;
background-color: rgba(0, 0, 0, 0.5);
color: white;
font-size: 24px;
display: flex;
align-items: center;
justify-content: center;
cursor: pointer;
opacity: 0;
visibility: hidden;
transition: opacity 0.3s ease, visibility 0.3s ease, background-color 0.3s ease;
box-shadow: 0 4px 8px rgba(0, 0, 0, 0.3);
z-index: 9999;
user-select: none;
touch-action: none;
}
#scroll-to-top-btn:hover {
background-color: rgba(0, 0, 0, 0.8);
box-shadow: 0 6px 12px rgba(0, 0, 0, 0.4);
}
#scroll-to-top-btn.show {
opacity: 0.8;
visibility: visible;
}
#scroll-to-top-btn.dragging {
cursor: grabbing;
background-color: rgba(0, 0, 0, 0.9);
}
`;
document.head.appendChild(style);
document.body.appendChild(button);
let isDragging = false;
let touchStartTime = 0;
let hideTimeout;
// Calculate 15% of page height
function get15PercentScroll() {
const documentHeight = document.documentElement.scrollHeight - window.innerHeight;
return documentHeight * 0.15;
}
// Hide button after 3 seconds of inactivity
function resetHideTimer() {
clearTimeout(hideTimeout);
hideTimeout = setTimeout(() => {
if (!isDragging) {
button.classList.remove('show');
}
}, 3000);
}
// Show/hide button based on scroll position
window.addEventListener('scroll', function() {
const scrollThreshold = get15PercentScroll();
const currentScroll = window.scrollY;
if (currentScroll > scrollThreshold) {
button.classList.add('show');
resetHideTimer();
} else {
button.classList.remove('show');
clearTimeout(hideTimeout);
}
});
// Show button on mouse/touch movement
document.addEventListener('mousemove', function() {
if (button.classList.contains('show') && !isDragging) {
resetHideTimer();
}
});
document.addEventListener('touchmove', function() {
if (button.classList.contains('show') && !isDragging) {
resetHideTimer();
}
});
// Smooth scroll to top on button click
button.addEventListener('click', function() {
if (!isDragging) {
window.scrollTo({
top: 0,
behavior: 'smooth'
});
}
});
// Handle drag on mouse
button.addEventListener('mousedown', function(e) {
touchStartTime = Date.now();
});
button.addEventListener('mousemove', function(e) {
if (touchStartTime && Date.now() - touchStartTime > 300) {
isDragging = true;
button.classList.add('dragging');
clearTimeout(hideTimeout);
}
});
document.addEventListener('mousemove', function(e) {
if (isDragging) {
button.style.bottom = (window.innerHeight - e.clientY) + 'px';
button.style.right = (window.innerWidth - e.clientX) + 'px';
}
});
document.addEventListener('mouseup', function() {
if (isDragging) {
isDragging = false;
button.classList.remove('dragging');
resetHideTimer();
}
touchStartTime = 0;
});
// Handle drag on touch
button.addEventListener('touchstart', function(e) {
touchStartTime = Date.now();
});
document.addEventListener('touchmove', function(e) {
if (touchStartTime && Date.now() - touchStartTime > 300 && button.classList.contains('show')) {
isDragging = true;
button.classList.add('dragging');
clearTimeout(hideTimeout);
const touch = e.touches[0];
button.style.bottom = (window.innerHeight - touch.clientY) + 'px';
button.style.right = (window.innerWidth - touch.clientX) + 'px';
}
});
document.addEventListener('touchend', function() {
if (isDragging) {
isDragging = false;
button.classList.remove('dragging');
resetHideTimer();
}
touchStartTime = 0;
});
// Recalculate threshold on window resize
window.addEventListener('resize', function() {
get15PercentScroll();
});
})();