Account Settings
FIRST NAME
[Loading...]
LAST NAME
[Loading...]
EMAIL
[Loading...]
ID
[Loading...] For support purposes only
Share AgencyGenius

Step 1: Add HTML, Css & JavaScript

Code
Html
Css
Javascript
Combined
 <!-- 
 Vanilla JS Scroll Progress Bar 
 - Shows scroll progress under the header 
 - Place this HTML code anywhere on your page 
 --> 
 <div id="vanilla-progress-bar-container"> 
 <div class="progress-bar-wrap"> 
 <div class="progress-bar"></div> 
 </div> 
 </div> 
 /* 
 Progress Bar Styles 
 - These styles will be applied to the progress bar container 
 - They'll be moved to the fixed container via JavaScript 
 */ 
  
 /* Initially hide the container - JS will create the fixed version */ 
 #vanilla-progress-bar-container { 
 display: none; 
 } 
  
 /* These styles will be applied to the fixed container created by JavaScript */ 
 #progress-bar-fixed-container { 
 position: fixed; 
 top: 0; /* Will be adjusted by JavaScript to position below header */ 
 left: 0; 
 width: 100vw; 
 height: 1.5rem; 
 z-index: 999; 
 } 
  
 #progress-bar-fixed-container .progress-bar-wrap { 
 width: 100%; 
 height: 100%; 
 cursor: pointer; 
 transition: background-color .2s; 
 } 
  
 #progress-bar-fixed-container .progress-bar-wrap:hover { 
 background-color: #0000000d; 
 } 
  
 #progress-bar-fixed-container .progress-bar { 
 transform-origin: 0%; 
 transform-style: preserve-3d; 
 background-color: #ad24a6; 
 width: 100%; 
 height: 100%; 
 transform: scale3d(0, 1, 1); 
 } 
 /** 
 * Vanilla JavaScript Progress Bar 
 * - Creates a progress bar that positions itself below the header 
 * - Tracks scroll progress and allows click-to-scroll functionality 
 */ 
 (function() { 
 // Self-executing function to create a closure and avoid global variables 
  
 // Function to initialize the progress bar when DOM is ready 
 function initProgressBar() { 
 // Get container reference to scope all our selectors 
 const container = document.getElementById('vanilla-progress-bar-container'); 
  
 // If container not found, exit 
 if (!container) return; 
  
 // Create a function to move the progress bar into the document body 
 function moveProgressBarToBody() { 
 // First, create a new container for the fixed progress bar 
 const fixedContainer = document.createElement('div'); 
 fixedContainer.id = 'progress-bar-fixed-container'; 
  
 // Clone the progress bar elements 
 const originalWrap = container.querySelector('.progress-bar-wrap'); 
 const progressBarWrap = originalWrap.cloneNode(true); 
  
 // Add to our fixed container 
 fixedContainer.appendChild(progressBarWrap); 
  
 // Add the fixed container to the body 
 document.body.appendChild(fixedContainer); 
  
 // Hide the original container 
 container.style.display = 'none'; 
  
 // Return references to the new elements 
 return { 
 container: fixedContainer, 
 wrap: progressBarWrap, 
 bar: progressBarWrap.querySelector('.progress-bar') 
 }; 
 } 
  
 // Move the progress bar to a fixed position in the body 
 const elements = moveProgressBarToBody(); 
 const progressBarContainer = elements.container; 
 const progressBarWrap = elements.wrap; 
 const progressBar = elements.bar; 
  
 // Function to position the progress bar under the header 
 function positionProgressBar() { 
 // Try to find header elements by common IDs and classes 
 // First check for Duda's header container 
 let header = document.getElementById('dmFlexHeaderContainer'); 
  
 // If Duda header isn't found, try other common header selectors 
 if (!header) { 
 // Try common header selectors 
 const commonHeaderSelectors = [ 
 'header', 
 '.header', 
 '#header', 
 '.site-header', 
 '.main-header', 
 '#site-header', 
 '.navbar', 
 '.navigation', 
 '.nav-container', 
 '.top-bar' 
 ]; 
  
 // Try each selector until we find a header 
 for (const selector of commonHeaderSelectors) { 
 header = document.querySelector(selector); 
 if (header) break; 
 } 
 } 
  
 // If we found a header, position the progress bar right below it 
 if (header) { 
 const headerRect = header.getBoundingClientRect(); 
 progressBarContainer.style.top = headerRect.bottom + 'px'; 
 } else { 
 // Fallback: if no header found, position at the top 
 progressBarContainer.style.top = '0px'; 
 } 
 } 
  
 // Position progress bar on load 
 positionProgressBar(); 
  
 // Reposition on window resize 
 window.addEventListener('resize', positionProgressBar); 
  
 // Function to update progress bar based on scroll position 
 function updateProgressBar() { 
 // Calculate scroll progress (0 to 1) 
 const scrollTop = window.scrollY || document.documentElement.scrollTop; 
 const scrollHeight = document.documentElement.scrollHeight; 
 const clientHeight = document.documentElement.clientHeight; 
 const scrollProgress = scrollTop / (scrollHeight - clientHeight); 
  
 // Ensure progress is between 0 and 1 to prevent visual glitches 
 const boundedProgress = Math.min(Math.max(scrollProgress, 0), 1); 
  
 // Update progress bar scale 
 progressBar.style.transform = `scale3d(${boundedProgress}, 1, 1)`; 
 } 
  
 // Initial update when page loads 
 updateProgressBar(); 
  
 // Add scroll event listener to update progress during scrolling 
 window.addEventListener('scroll', updateProgressBar); 
  
 // Click listener to scroll to a specific position (optional feature) 
 progressBarWrap.addEventListener('click', (event) => { 
 // Calculate the horizontal position of the click as a percentage 
 const clickX = event.clientX; 
 const progress = clickX / progressBarWrap.offsetWidth; 
  
 // Calculate the actual scroll position based on that percentage 
 const scrollPosition = progress * (document.body.scrollHeight - window.innerHeight); 
  
 // Smooth scroll to that position 
 smoothScrollTo(scrollPosition, 725); // 725ms animation duration 
 }); 
  
 /** 
 * Smooth scroll function for animated scrolling 
 * @param {number} targetPosition - Target scroll position in pixels 
 * @param {number} duration - Animation duration in milliseconds 
 */ 
 function smoothScrollTo(targetPosition, duration) { 
 const startPosition = window.scrollY || document.documentElement.scrollTop; 
 const distance = targetPosition - startPosition; 
 const startTime = performance.now(); 
  
 function scrollAnimation(currentTime) { 
 const elapsedTime = currentTime - startTime; 
 const progress = Math.min(elapsedTime / duration, 1); // Clamp to 1 
  
 // Use cubic easing for smooth animation 
 const easeProgress = 1 - Math.pow(1 - progress, 3); 
  
 window.scrollTo(0, startPosition + distance * easeProgress); 
  
 // Continue animation if not complete 
 if (progress < 1) { 
 requestAnimationFrame(scrollAnimation); 
 } 
 } 
  
 // Start the animation 
 requestAnimationFrame(scrollAnimation); 
 } 
 } 
  
 // Initialize when DOM is ready 
 if (document.readyState === 'loading') { 
 document.addEventListener('DOMContentLoaded', initProgressBar); 
 } else { 
 // DOM already loaded, initialize immediately 
 initProgressBar(); 
 } 
 })(); 
 <div id="snippet-4evbhub1"> 
 <!-- HTML SECTION START --> 
 <!-- 
 Vanilla JS Scroll Progress Bar 
 - Shows scroll progress under the header 
 - Place this HTML code anywhere on your page 
 --> 
 <div id="vanilla-progress-bar-container"> 
 <div class="progress-bar-wrap"> 
 <div class="progress-bar"></div> 
 </div> 
 </div> 
 <!-- HTML SECTION END --> 
  
 <!-- CSS SECTION START --> 
 <style> 
 /* 
 Progress Bar Styles 
 - These styles will be applied to the progress bar container 
 - They'll be moved to the fixed container via JavaScript 
 */ 
  
 /* Initially hide the container - JS will create the fixed version */ 
 #vanilla-progress-bar-container { 
 display: none; 
 } 
  
 /* These styles will be applied to the fixed container created by JavaScript */ 
 #progress-bar-fixed-container { 
 position: fixed; 
 top: 0; /* Will be adjusted by JavaScript to position below header */ 
 left: 0; 
 width: 100vw; 
 height: 1.5rem; 
 z-index: 999; 
 } 
  
 #progress-bar-fixed-container .progress-bar-wrap { 
 width: 100%; 
 height: 100%; 
 cursor: pointer; 
 transition: background-color .2s; 
 } 
  
 #progress-bar-fixed-container .progress-bar-wrap:hover { 
 background-color: #0000000d; 
 } 
  
 #progress-bar-fixed-container .progress-bar { 
 transform-origin: 0%; 
 transform-style: preserve-3d; 
 background-color: #ad24a6; 
 width: 100%; 
 height: 100%; 
 transform: scale3d(0, 1, 1); 
 } 
 </style> 
 <!-- CSS SECTION END --> 
  
 <!-- JAVASCRIPT SECTION START --> 
 <script> 
 /** 
 * Vanilla JavaScript Progress Bar 
 * - Creates a progress bar that positions itself below the header 
 * - Tracks scroll progress and allows click-to-scroll functionality 
 */ 
 (function() { 
 // Self-executing function to create a closure and avoid global variables 
  
 // Function to initialize the progress bar when DOM is ready 
 function initProgressBar() { 
 // Get container reference to scope all our selectors 
 const container = document.getElementById('vanilla-progress-bar-container'); 
  
 // If container not found, exit 
 if (!container) return; 
  
 // Create a function to move the progress bar into the document body 
 function moveProgressBarToBody() { 
 // First, create a new container for the fixed progress bar 
 const fixedContainer = document.createElement('div'); 
 fixedContainer.id = 'progress-bar-fixed-container'; 
  
 // Clone the progress bar elements 
 const originalWrap = container.querySelector('.progress-bar-wrap'); 
 const progressBarWrap = originalWrap.cloneNode(true); 
  
 // Add to our fixed container 
 fixedContainer.appendChild(progressBarWrap); 
  
 // Add the fixed container to the body 
 document.body.appendChild(fixedContainer); 
  
 // Hide the original container 
 container.style.display = 'none'; 
  
 // Return references to the new elements 
 return { 
 container: fixedContainer, 
 wrap: progressBarWrap, 
 bar: progressBarWrap.querySelector('.progress-bar') 
 }; 
 } 
  
 // Move the progress bar to a fixed position in the body 
 const elements = moveProgressBarToBody(); 
 const progressBarContainer = elements.container; 
 const progressBarWrap = elements.wrap; 
 const progressBar = elements.bar; 
  
 // Function to position the progress bar under the header 
 function positionProgressBar() { 
 // Try to find header elements by common IDs and classes 
 // First check for Duda's header container 
 let header = document.getElementById('dmFlexHeaderContainer'); 
  
 // If Duda header isn't found, try other common header selectors 
 if (!header) { 
 // Try common header selectors 
 const commonHeaderSelectors = [ 
 'header', 
 '.header', 
 '#header', 
 '.site-header', 
 '.main-header', 
 '#site-header', 
 '.navbar', 
 '.navigation', 
 '.nav-container', 
 '.top-bar' 
 ]; 
  
 // Try each selector until we find a header 
 for (const selector of commonHeaderSelectors) { 
 header = document.querySelector(selector); 
 if (header) break; 
 } 
 } 
  
 // If we found a header, position the progress bar right below it 
 if (header) { 
 const headerRect = header.getBoundingClientRect(); 
 progressBarContainer.style.top = headerRect.bottom + 'px'; 
 } else { 
 // Fallback: if no header found, position at the top 
 progressBarContainer.style.top = '0px'; 
 } 
 } 
  
 // Position progress bar on load 
 positionProgressBar(); 
  
 // Reposition on window resize 
 window.addEventListener('resize', positionProgressBar); 
  
 // Function to update progress bar based on scroll position 
 function updateProgressBar() { 
 // Calculate scroll progress (0 to 1) 
 const scrollTop = window.scrollY || document.documentElement.scrollTop; 
 const scrollHeight = document.documentElement.scrollHeight; 
 const clientHeight = document.documentElement.clientHeight; 
 const scrollProgress = scrollTop / (scrollHeight - clientHeight); 
  
 // Ensure progress is between 0 and 1 to prevent visual glitches 
 const boundedProgress = Math.min(Math.max(scrollProgress, 0), 1); 
  
 // Update progress bar scale 
 progressBar.style.transform = `scale3d(${boundedProgress}, 1, 1)`; 
 } 
  
 // Initial update when page loads 
 updateProgressBar(); 
  
 // Add scroll event listener to update progress during scrolling 
 window.addEventListener('scroll', updateProgressBar); 
  
 // Click listener to scroll to a specific position (optional feature) 
 progressBarWrap.addEventListener('click', (event) => { 
 // Calculate the horizontal position of the click as a percentage 
 const clickX = event.clientX; 
 const progress = clickX / progressBarWrap.offsetWidth; 
  
 // Calculate the actual scroll position based on that percentage 
 const scrollPosition = progress * (document.body.scrollHeight - window.innerHeight); 
  
 // Smooth scroll to that position 
 smoothScrollTo(scrollPosition, 725); // 725ms animation duration 
 }); 
  
 /** 
 * Smooth scroll function for animated scrolling 
 * @param {number} targetPosition - Target scroll position in pixels 
 * @param {number} duration - Animation duration in milliseconds 
 */ 
 function smoothScrollTo(targetPosition, duration) { 
 const startPosition = window.scrollY || document.documentElement.scrollTop; 
 const distance = targetPosition - startPosition; 
 const startTime = performance.now(); 
  
 function scrollAnimation(currentTime) { 
 const elapsedTime = currentTime - startTime; 
 const progress = Math.min(elapsedTime / duration, 1); // Clamp to 1 
  
 // Use cubic easing for smooth animation 
 const easeProgress = 1 - Math.pow(1 - progress, 3); 
  
 window.scrollTo(0, startPosition + distance * easeProgress); 
  
 // Continue animation if not complete 
 if (progress < 1) { 
 requestAnimationFrame(scrollAnimation); 
 } 
 } 
  
 // Start the animation 
 requestAnimationFrame(scrollAnimation); 
 } 
 } 
  
 // Initialize when DOM is ready 
 if (document.readyState === 'loading') { 
 document.addEventListener('DOMContentLoaded', initProgressBar); 
 } else { 
 // DOM already loaded, initialize immediately 
 initProgressBar(); 
 } 
 })(); 
 </script> 
 <!-- JAVASCRIPT SECTION END --> 
 </div> 

Implementation

The Vanilla JS Progress Bar creates a sleek, fixed-position scroll indicator that positions itself beneath your website's header. As users scroll down the page, the bar fills proportionally to represent their progress. The implementation also includes an optional click-to-scroll feature that allows users to jump to different parts of the page by clicking on the bar.

HTML Structure

The HTML structure is minimal and can be placed anywhere on your page:

  • A container vanilla-progress-bar-container holds the basic structure
  • Inside is a wrapper progress-bar-wrap which handles user interaction
  • The actual indicator progress-bar shows the scroll progress
CSS Styling

The CSS handles positioning, appearance, and animations:

  • Uses position: fixed to keep the bar in view at all times
  • Sets width: 100vw to ensure the bar spans the full viewport width
  • Uses z-index: 999 to display above other page elements
  • Creates a subtle hover effect with background-color: #0000000d
  • The progress indicator uses transform: scale3d() for smooth performance
  • Sets background-color: #ad24a6 for the purple progress indicator
  • Uses transform-origin: 0% to ensure scaling happens from left to right
JavaScript Functionality

The JavaScript handles dynamic positioning and interaction:

  • Header Detection:
    • Automatically finds your site's header element
    • First looks for Duda's #dmFlexHeaderContainer
    • Falls back to common header selectors if Duda's header isn't found
  • Element Creation:
    • Creates a fixed container directly in the document body
    • Moves the progress bar into this container for proper positioning
    • Positions the bar immediately below the detected header
  • Scroll Tracking:
    • Calculates current scroll position relative to total page height
    • Updates the scale3d transform to represent scroll percentage
    • Ensures values are bounded between 0 and 1 to prevent visual glitches
  • Click Navigation:
    • Captures click position relative to the bar width
    • Calculates corresponding scroll position as a percentage of total page height
    • Implements smooth scrolling with cubic easing function
    • Uses requestAnimationFrame for butter-smooth animations
Customization Tips

The progress bar can be easily customized to match your site:

  • Bar color: Change the background-color property of .progress-bar
  • Bar height: Adjust the height property in both the container and progress bar
  • Animation speed: Modify the duration parameter in the smoothScrollTo function
  • Hover effect: Customize the background-color value for .progress-bar-wrap:hover
  • Z-index: Adjust the z-index value if the bar needs to appear above or below certain elements
  • Header detection: Add additional selectors to the commonHeaderSelectors array for custom headers
Integration Tips

To integrate this widget into your site:

  • Placement: Add the HTML code anywhere on pages where you want the progress bar to appear
  • Styling conflicts: If your site already uses similar class names, change the IDs and class names in the code
  • Multiple instances: The script prevents duplicate progress bars if you accidentally add it multiple times
  • Click navigation: Remove the click event listener code if you don't want the click-to-scroll functionality
  • Performance: The code uses efficient transform properties and requestAnimationFrame for smooth performance
  • Responsive design: The progress bar automatically adjusts on window resize to stay below the header
Video Thumbnail

How to edit code using AI

Resource Details:
Vanilla JS Progress Bar adds a sleek scroll indicator beneath your site's header. The bar fills as users scroll, visually showing their position on the page. Features automatic header detection, click-to-navigate functionality, and smooth animations. Pure JavaScript implementation with no dependencies, customizable colors, and responsive positioning that works across different platforms and screen sizes.

Last Updated:

April 20th 2025

Category:

Image Display

Need Help?

Join Slack

Callum Wells
Callum Wells
i
Creator Credits
We always strive to credit creators as accurately as possible. While similar concepts might appear online, we aim to provide proper and respectful attribution.
A black padlock with a keyhole on a white background.

NO-ACCESS

Only for Desktop Users

This page is only available on desktop.

Please Log in on a desktop to gain access.