<script type="module" src="https://unpkg.com/ionicons@7.1.0/dist/ionicons/ionicons.esm.js"></script>
<script nomodule src="https://unpkg.com/ionicons@7.1.0/dist/ionicons/ionicons.js"></script>
<div class="header">
<h1>Scroll to Top Demo</h1>
<p>Scroll down to see the animated scroll-to-top button appear</p>
</div>
<div class="content">
<div class="card">
<h2>What is a Scroll to Top Button?</h2>
<p>A scroll to top button is a user interface element that allows users to quickly navigate back to the top of a webpage with a single click. It's especially useful on long pages with lots of content.</p>
<p>This implementation features smooth scrolling animation, progressive appearance based on scroll position, and a circular progress indicator showing your current scroll depth.</p>
</div>
<div class="demo-info">
<h4>✨ Features of This Implementation:</h4>
<ul>
<li>Smooth scroll animation to top</li>
<li>Auto-hide/show based on scroll position</li>
<li>Circular progress ring showing scroll depth</li>
<li>Hover effects and animations</li>
<li>Responsive design for all devices</li>
<li>Uses modern CSS and vanilla JavaScript</li>
</ul>
</div>
<div class="card">
<h2>How It Works</h2>
<p>The button appears when you scroll down more than 300 pixels from the top of the page. As you scroll, the circular progress ring fills up to show how far down the page you've scrolled.</p>
<p>Click the button at any time to smoothly scroll back to the top of the page. The animation uses the browser's native smooth scrolling behavior for optimal performance.</p>
</div>
<div class="feature-box">
<h3>🎯 Best Practices</h3>
<p>Scroll to top buttons should be placed in a fixed position, typically in the bottom-right corner of the viewport. They should be unobtrusive but easily accessible when needed.</p>
</div>
<div class="card">
<h2>Benefits for User Experience</h2>
<p>Navigation Enhancement: Users can quickly return to the top without manually scrolling, especially important on mobile devices where scrolling long distances can be tedious.</p>
<p>Accessibility: Provides an alternative navigation method for users who may have difficulty with traditional scrolling mechanisms.</p>
<p>Professional Polish: Adds a modern, polished feel to your website and shows attention to user experience details.</p>
</div>
<div class="card">
<h2>Implementation Details</h2>
<p>This implementation uses pure vanilla JavaScript with no dependencies. The scroll detection uses the window scroll event with throttling for optimal performance.</p>
<p>The progress ring is created using SVG and updates in real-time as the user scrolls. The button uses CSS transforms for smooth animations and transitions.</p>
</div>
<div class="feature-box">
<h3>💡 Did You Know?</h3>
<p>The scroll-to-top pattern became popular in the early 2010s as websites began featuring longer, single-page layouts. Today, it's considered a standard UI pattern for content-heavy websites.</p>
</div>
<div class="card">
<h2>Customization Options</h2>
<p>You can easily customize the appearance by modifying the CSS variables. Change the gradient colors, button size, position, or animation timing to match your brand.</p>
<p>The trigger point (when the button appears) can be adjusted by changing the scroll threshold value in the JavaScript code.</p>
</div>
<div class="card">
<h2>Browser Compatibility</h2>
<p>This implementation works in all modern browsers including Chrome, Firefox, Safari, and Edge. The smooth scroll behavior is supported natively in most browsers, with a fallback for older versions.</p>
<p>The SVG progress ring is widely supported across all browsers and provides a lightweight, scalable solution for the visual indicator.</p>
</div>
<div class="card">
<h2>Keep Scrolling</h2>
<p>Continue scrolling to see more content and test the scroll-to-top functionality. Notice how the progress ring fills up as you scroll down the page.</p>
<p>The button will become visible once you've scrolled past a certain threshold, making it available whenever you need to quickly return to the top.</p>
</div>
<div class="feature-box">
<h3>🚀 Performance</h3>
<p>This implementation is optimized for performance with minimal JavaScript execution. Event listeners are efficiently managed and animations use CSS transforms for hardware acceleration.</p>
</div>
<div class="card">
<h2>Final Thoughts</h2>
<p>A well-implemented scroll-to-top button enhances user experience without being intrusive. It's a small detail that can make a big difference in how users interact with your content.</p>
<p>Try clicking the button now to see the smooth scroll animation in action!</p>
</div>
</div>
<footer>
<p>Scroll to Top Demo • Built with HTML, CSS & JavaScript</p>
<p style="margin-top: 10px; color: #999;">Scroll down to see the button appear ↓</p>
</footer>
<button class="scroll-to-top" id="scrollToTop" aria-label="Scroll to top">
<svg class="progress-ring">
<circle class="progress-ring-circle" cx="28" cy="28" r="24"></circle>
<circle class="progress-ring-progress" cx="28" cy="28" r="24" id="progressCircle"></circle>
</svg>
<ion-icon name="arrow-up-outline"></ion-icon>
</button>
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
html {
scroll-behavior: smooth;
}
body {
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell, sans-serif;
background: linear-gradient(to bottom, #0d7377 0%, #14ffec 50%, #20b2aa 100%);
color: #333;
}
.header {
background: rgba(255, 255, 255, 0.95);
backdrop-filter: blur(10px);
padding: 30px;
text-align: center;
box-shadow: 0 2px 20px rgba(0, 0, 0, 0.1);
position: sticky;
top: 0;
z-index: 100;
}
.header h1 {
font-size: 32px;
color: #0d7377;
margin-bottom: 10px;
}
.header p {
color: #666;
font-size: 16px;
}
.content {
max-width: 800px;
margin: 0 auto;
padding: 60px 30px;
}
.card {
background: white;
border-radius: 16px;
padding: 40px;
margin-bottom: 40px;
box-shadow: 0 10px 40px rgba(0, 0, 0, 0.1);
}
.card h2 {
font-size: 28px;
color: #0d7377;
margin-bottom: 20px;
}
.card p {
line-height: 1.8;
color: #555;
margin-bottom: 15px;
font-size: 16px;
}
.feature-box {
background: linear-gradient(135deg, #0d7377 0%, #20b2aa 100%);
color: white;
padding: 30px;
border-radius: 12px;
margin: 20px 0;
}
.feature-box h3 {
margin-bottom: 15px;
font-size: 20px;
}
.scroll-to-top {
position: fixed;
bottom: 30px;
right: 30px;
width: 56px;
height: 56px;
background: linear-gradient(135deg, #0d7377 0%, #20b2aa 100%);
border: none;
border-radius: 50%;
cursor: pointer;
display: flex;
align-items: center;
justify-content: center;
box-shadow: 0 8px 25px rgba(13, 115, 119, 0.4);
transition: all 0.3s ease;
opacity: 0;
visibility: hidden;
transform: scale(0.8);
z-index: 1000;
}
.scroll-to-top.visible {
opacity: 1;
visibility: visible;
transform: scale(1);
}
.scroll-to-top:hover {
transform: scale(1.1);
box-shadow: 0 12px 35px rgba(13, 115, 119, 0.6);
}
.scroll-to-top:active {
transform: scale(0.95);
}
.scroll-to-top ion-icon {
font-size: 28px;
color: white;
}
.progress-ring {
position: absolute;
top: 0;
left: 0;
width: 56px;
height: 56px;
transform: rotate(-90deg);
}
.progress-ring-circle {
stroke: rgba(255, 255, 255, 0.3);
fill: none;
stroke-width: 3;
}
.progress-ring-progress {
stroke: white;
fill: none;
stroke-width: 3;
stroke-linecap: round;
transition: stroke-dashoffset 0.1s linear;
}
.demo-info {
background: #e0f7f7;
border-left: 4px solid #0d7377;
padding: 20px;
border-radius: 8px;
margin: 30px 0;
}
.demo-info h4 {
color: #0d7377;
margin-bottom: 10px;
font-size: 18px;
}
.demo-info ul {
margin-left: 20px;
color: #555;
}
.demo-info li {
margin: 8px 0;
}
footer {
background: rgba(255, 255, 255, 0.95);
padding: 40px;
text-align: center;
color: #666;
margin-top: 60px;
}
</style>
</head>
<body>
const scrollToTopBtn = document.getElementById('scrollToTop');
const progressCircle = document.getElementById('progressCircle');
const circumference = 2 * Math.PI * 24;
progressCircle.style.strokeDasharray = circumference;
progressCircle.style.strokeDashoffset = circumference;
window.addEventListener('scroll', () => {
const scrollTop = window.pageYOffset || document.documentElement.scrollTop;
const scrollHeight = document.documentElement.scrollHeight - document.documentElement.clientHeight;
const scrollPercentage = (scrollTop / scrollHeight) * 100;
if (scrollTop > 300) {
scrollToTopBtn.classList.add('visible');
} else {
scrollToTopBtn.classList.remove('visible');
}
const offset = circumference - (scrollPercentage / 100) * circumference;
progressCircle.style.strokeDashoffset = offset;
});
scrollToTopBtn.addEventListener('click', (e) => {
e.preventDefault();
const duration = 800;
const start = window.pageYOffset;
const startTime = performance.now();
function animation(currentTime) {
const elapsedTime = currentTime - startTime;
const progress = Math.min(elapsedTime / duration, 1);
const easeInOutQuad = progress < 0.5
? 2 * progress * progress
: 1 - Math.pow(-2 * progress + 2, 2) / 2;
window.scrollTo(0, start * (1 - easeInOutQuad));
if (progress < 1) {
requestAnimationFrame(animation);
}
}
requestAnimationFrame(animation);
});
No comments yet. Be the first!