Vanilla ES6 滚动固定区块后窗口大小调整问题求助
Fixing Window Resize Issues for Scroll-Stuck Sections in Vanilla ES6
Got it, let's work through this problem. When implementing scroll-stuck sections in plain ES6, window resizes can throw off your position calculations because the dimensions and offsets of your elements change as the viewport size shifts. Here's a robust, performant solution tailored to your HTML structure:
Step 1: Complete & Structure Your HTML
First, let's finish up that partial HTML you shared (adding a proper footer for context):
<header class="forewords"> <h1>Lorem some</h1> </header> <div class="wrapper"> <section class="project" id="item1">this is section 1</section> <section class="project" id="item2">this is section 2</section> <section class="project" id="item3">this is section 3</section> </div> <footer class="page-footer"> <p>Footer content here</p> </footer>
Step 2: Base CSS for Sticky Behavior
Add styles to define your sections' default state and the "stuck" fixed state:
* { margin: 0; padding: 0; box-sizing: border-box; } .forewords { padding: 2rem; background: #f0f0f0; } .wrapper { position: relative; min-height: calc(100vh - 8rem); /* Adjust based on header/footer height */ } .project { height: 100vh; padding: 2rem; border-bottom: 1px solid #ddd; background: #fff; } /* Class for when a section is fixed to the top */ .project.stuck { position: fixed; top: 0; left: 0; right: 0; height: auto; /* Keep content height, or set to 100vh for full viewport */ box-shadow: 0 2px 4px rgba(0,0,0,0.1); z-index: 10; }
Step 3: ES6 JavaScript with Resize Handling
This script handles scroll detection, position recalculation on resize, and uses debouncing to avoid performance hits:
// Debounce utility to limit resize event frequency const debounce = (func, delay = 150) => { let timeoutId; return (...args) => { clearTimeout(timeoutId); timeoutId = setTimeout(() => func.apply(this, args), delay); }; }; // Track critical element data let headerHeight; let sectionData = []; let activeStuckSection = null; // Initialize/re-calculate element positions (called on load + resize) const updateSectionPositions = () => { // Get updated header height headerHeight = document.querySelector('.forewords').offsetHeight; // Reset and rebuild section position data sectionData = []; document.querySelectorAll('.project').forEach(section => { const rect = section.getBoundingClientRect(); sectionData.push({ element: section, topOffset: rect.top + window.scrollY, // Position relative to document top height: rect.height }); }); // Re-check scroll position to update stuck state immediately after resize checkScrollState(); }; // Determine which section should be stuck based on scroll position const checkScrollState = () => { const scrollPosition = window.scrollY; const wrapper = document.querySelector('.wrapper'); // Loop through sections to find the active one to stick sectionData.forEach((section, index) => { const nextSection = sectionData[index + 1]; // Calculate when this section should stick/unstick const stickThreshold = section.topOffset - headerHeight; const unstickThreshold = nextSection ? nextSection.topOffset - headerHeight : Infinity; if (scrollPosition >= stickThreshold && scrollPosition < unstickThreshold) { // Only update if the active section changed if (activeStuckSection !== section.element) { // Remove stuck state from previous section if (activeStuckSection) { activeStuckSection.classList.remove('stuck'); wrapper.style.paddingTop = '0'; } // Apply stuck state to current section section.element.classList.add('stuck'); // Add padding to wrapper to fill the gap left by the fixed element wrapper.style.paddingTop = `${section.height}px`; activeStuckSection = section.element; } } else if (section.element.classList.contains('stuck')) { section.element.classList.remove('stuck'); } }); // Reset state if scrolled above the first section if (scrollPosition < sectionData[0].topOffset - headerHeight && activeStuckSection) { activeStuckSection.classList.remove('stuck'); wrapper.style.paddingTop = '0'; activeStuckSection = null; } }; // Initialize everything on page load document.addEventListener('DOMContentLoaded', () => { updateSectionPositions(); window.addEventListener('scroll', checkScrollState); // Use debounced resize handler to avoid excessive calculations window.addEventListener('resize', debounce(updateSectionPositions)); });
Key Details to Note:
- Debouncing: The
debouncefunction ensures we don't recalculate positions every single time the resize event fires (which can be hundreds of times per second), keeping the UI smooth. - Dynamic Position Updates:
updateSectionPositionsre-fetches element dimensions and offsets on every resize, so your stuck logic always uses accurate, up-to-date values. - Content Jump Prevention: We adjust the wrapper's
paddingTopwhen a section is fixed to avoid sudden layout shifts caused by the fixed element leaving the document flow.
内容的提问来源于stack exchange,提问作者—
相关产品推荐
相关产品推荐

