You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

滚动时切换页面背景色的Vanilla JS实现求助

Fixing & Optimizing Your Vanilla JS Scroll-Based Background Switcher

Hey there! Let's break down what's going wrong with your current code and build a working, efficient version of your scroll-triggered background color changer.

First, Let's Diagnose the Issues in Your Original Code

  • Broken Class Storage: When you run let cyan = bdy.classList.add('lightCyan');, classList.add() returns undefined—so your colors array ends up filled with nothing but undefined values. That's why the loop in your scroll event does nothing useful.
  • Incorrect Scroll Condition: Your condition document.documentElement.scrollTop || document.body.scrollTop > window.innerHeight is logically flawed. The || operator here doesn't group the scrollTop values together properly, so it's only checking if document.body.scrollTop is greater than the viewport height.
  • Wrong Class Switching Logic: The loop where you push i into colors doesn't actually toggle or switch any classes on the body—it just adds numbers to an array, which doesn't affect the DOM at all.

Working Fixed Code

Let's rewrite the JavaScript to properly handle scroll positions and class switching, plus tweak the CSS for better layout.

HTML (No Changes Needed)

<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<link rel="css\style.css">
<title>Site experiment</title>
</head>
<body>
<section>
<h1 id="first-h1">This site is an experiment on scroll effects</h1>
</section>
<section>
<h1 id="second-h1">I really hope this helps me learn vanilla JavaScript better</h1>
</section>
<section>
<h1 id="third-h1">I think it will honestly</h1>
</section>
<section>
<h1 id="fourth-h1">Or maybe it will frustrate me till the end of time</h1>
</section>
<section>
<h1 id="fifth-h1">Even if that does happen, I'll still keep trying</h1>
</section>
</body>
<script src="js\app.js"></script>
</html>

CSS (Tweaked for Better Centering)

@import url('https://fonts.googleapis.com/css?family=Roboto+Mono');
* {
margin: 0;
padding: 0;
box-sizing: border-box;
font-family: 'Roboto Mono', monospace;
}
body {
background-color: #E5E1EE;
transition: background-color 0.3s ease; /* More specific transition */
}
section {
height: 100vh;
display: flex; /* Center heading vertically/horizontally */
align-items: center;
justify-content: center;
padding: 2rem;
}
h1 {
text-align: center;
max-width: 80%;
}
.lightCyan {
background-color: #DFFDFF;
}
.darkSkyBlue {
background-color: #90BEDE;
}
.aquamarine {
background-color: #68EDC6;
}
.electricBlue {
background-color: #90F3FF;
}

JavaScript (Fixed & Functional)

const body = document.querySelector('body');
const sections = document.querySelectorAll('section');
// Map each section to its corresponding background class
const sectionColorMap = [
  '', // First section uses default body color
  'lightCyan',
  'darkSkyBlue',
  'aquamarine',
  'electricBlue'
];

function handleScroll() {
  // Get current scroll position (cross-browser support)
  const scrollPos = window.scrollY || document.documentElement.scrollTop;
  const viewportHeight = window.innerHeight;

  // Loop through sections to find which one is currently in view
  sections.forEach((section, index) => {
    const sectionTop = section.offsetTop;
    // Trigger when we've scrolled to the middle of the section
    if (scrollPos >= sectionTop - viewportHeight / 2) {
      // Remove all existing color classes first
      body.classList.remove('lightCyan', 'darkSkyBlue', 'aquamarine', 'electricBlue');
      // Add the corresponding color class for this section
      if (sectionColorMap[index]) {
        body.classList.add(sectionColorMap[index]);
      }
    }
  });
}

// Add scroll event listener
window.addEventListener('scroll', handleScroll);
// Run once on page load to set initial state
handleScroll();

Optimization Tips for Better Performance

  • Throttle the Scroll Event: Scroll events fire hundreds of times per second, which can cause jank. Add a throttle function to limit how often handleScroll runs:
    function throttle(func, delay = 100) {
      let lastCall = 0;
      return (...args) => {
        const now = Date.now();
        if (now - lastCall >= delay) {
          func(...args);
          lastCall = now;
        }
      };
    }
    // Use throttled version in event listener
    window.addEventListener('scroll', throttle(handleScroll));
    
  • Use Intersection Observer API: For even better performance (especially on mobile), replace the scroll listener with an Intersection Observer. This API is designed to detect when elements enter/exit the viewport without listening to scroll events:
    const observerOptions = {
      root: null, // Use viewport as root
      rootMargin: '-50% 0px -50% 0px', // Trigger when section is centered in viewport
      threshold: 0
    };
    
    const observer = new IntersectionObserver((entries) => {
      entries.forEach(entry => {
        if (entry.isIntersecting) {
          const sectionIndex = Array.from(sections).indexOf(entry.target);
          body.classList.remove('lightCyan', 'darkSkyBlue', 'aquamarine', 'electricBlue');
          if (sectionColorMap[sectionIndex]) {
            body.classList.add(sectionColorMap[sectionIndex]);
          }
        }
      });
    }, observerOptions);
    
    // Observe each section
    sections.forEach(section => observer.observe(section));
    
  • Preselect Elements: We already do this with const sections = document.querySelectorAll('section')—avoid querying the DOM inside scroll/observer callbacks, as DOM queries are expensive.

内容的提问来源于stack exchange,提问作者eddiepearson

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.13 07:43:50