原生JavaScript页面滚动进度条实现问题求助
Hey there! Let’s walk through each of your problems and get that scroll progress bar working as expected.
1. Why document.body.scrollTop always returns 0
You already nailed the fix with document.scrollingElement.scrollTop—great call! Here’s the breakdown:
- Browsers have inconsistent default scroll elements: Chrome and Edge use the
<html>element, while older Firefox versions relied on<body>. document.scrollingElementis the standard, cross-browser way to grab the root element that handles page scrolling. Stick with this for all scroll-related calculations.
2. Fixing the progress calculation offset issue
Your core logic is almost right, but the problem comes from mismatched elements in your height calculation. You’re using document.body.scrollHeight but should pair it with the same scrolling element you use for scrollTop. Here’s the corrected code:
const progressBar = document.getElementById('footer__progress_bar'); let totalValue; // Calculate total scrollable height (and update on resize) const updateTotalValue = () => { totalValue = document.scrollingElement.scrollHeight - window.innerHeight; }; // Initialize on page load updateTotalValue(); // Update when window size changes window.addEventListener('resize', updateTotalValue); document.body.onscroll = () => { const currentValue = document.scrollingElement.scrollTop; // Avoid division by zero if page is shorter than viewport if (totalValue <= 0) { progressBar.style.left = '0%'; return; } // Your original logic works once totalValue is accurate const offset = (currentValue / totalValue) * 100 - 100 + '%'; progressBar.style.left = offset; };
Key improvements here:
- Use
document.scrollingElement.scrollHeightinstead ofdocument.body.scrollHeightfor consistent, accurate total height. - Add a resize listener to update
totalValuewhen the window resizes (this fixes offset glitches from viewport changes). - Add a guard clause to prevent division by zero if the page content is shorter than the viewport.
3. Why page height values (clientHeight/offsetHeight) are inconsistent
The random fluctuations you’re seeing are likely caused by:
- Unloaded assets: Images, fonts, or dynamic content loading after your initial height check, which shifts the page’s total height.
- Browser scrollbar space:
window.innerHeightexcludes the scrollbar (if present), which can change depending on whether content overflows. - CSS box model differences:
clientHeightignores borders and scrollbars, whileoffsetHeightincludes them. If your<body>has padding or borders, these values will naturally differ.
To fix this:
- Stick with
document.scrollingElement.scrollHeightfor the full page height—it accounts for all content, including dynamically loaded elements. - Wait for all assets to load before calculating heights (use
window.onloadinstead ofDOMContentLoadedif you have images, or listen forloadevents on specific assets).
4. Why main.scrollTop returns 0
scrollTop only has a non-zero value when an element has a scrollbar—meaning its content overflows its defined height, and overflow is set to auto or scroll. Since you’ve set main to height: auto, it expands to fit its content, so there’s no overflow to scroll through.
If you wanted <main> to scroll independently of the page, you’d need to:
- Set a fixed height on
<main>(e.g.,height: 100vh;) - Add
overflow-y: auto;to it - Listen for scroll events on
<main>instead of the document.
But since your goal is a page-wide scroll progress bar, sticking with document.scrollingElement is the right call.
内容的提问来源于stack exchange,提问作者oldboy

