如何用JavaScript实现滚动吸附时背景色匹配对应Div颜色?
解决Scroll-Snap吸附时同步页面背景色的问题
核心方案
用原生Intersection Observer API监听滚动吸附的元素,当元素滚动到视口中心时,同步更新页面背景色。这个API无需依赖任何库,刚好适配你的需求,比用scrollY/offsetTop的方式更精准。
实现步骤
- 初始化时把每个
.book的背景色存入自定义属性,方便后续直接获取 - 配置Intersection Observer,将观察区域定位到视口中心,确保只有元素吸附到中心时触发回调
- 监听元素交叉状态,触发时更新页面背景色
修改后的完整代码
HTML(无改动)
<div id="background" class="container"> <header> <h2>BACKSTAGE TALKS</h2> </header> <div class="info"> <p> Backstage Talks is a magazine <br> casual, but in depth dialogues <br> on design and business. Our decisions <br> shape and influence this complex <br> world—to have a chance to make the <br> right ones, we need to talk </p> </div> <div id="scroll-box" class="scroller"> <div class="book" id="book_issue-1">1</div> <div class="book" id="book_issue-2">2</div> <div class="book" id="book_issue-3">3</div> <div class="book" id="book_issue-4">4</div> <div class="book" id="book_issue-5">5</div> <div class="book" id="book_issue-6">6</div> </div> <div class="links"> <h2>info@backstagetalks.com</h2> <div class="issue-list"> <p id="issue1"><a href="#book_issue-1">Issue #1</a></p> <p id="issue2"><a href="#book_issue-2">Issue #2</a></p> <p id="issue3"><a href="#book_issue-3">Issue #3</a></p> <p id="issue4"><a href="#book_issue-4">Issue #4</a></p> <p id="issue5"><a href="#book_issue-5">Issue #5</a></p> <p id="issue6"><a href="#book_issue-6">Issue #6</a></p> </div> </div> </div>
CSS(无改动)
@import url('https://fonts.googleapis.com/css2?family=Bangers&family=Chivo+Mono:ital,wght@1,500&family=Hanalei+Fill&family=Fredoka+One&display=swap'); html, body{ margin: 0; /* font-family: Arial, Helvetica, sans-serif; */ } ::-webkit-scrollbar { display: none; } header { padding: 0.7em 0 0 0 ; color: red; font-family: 'Bangers'; font-size: 25px; } header h2 { margin: 0; } .container { height: 100vh; display: flex; justify-content: space-between; /* border: 2px solid brown; */ } .scroller { max-height: 100vh; overflow: scroll; scroll-snap-type: y mandatory; margin: 0 auto; width: 100%; position: absolute; scroll-behavior: smooth; z-index: 1; } .book { /* border: 20px solid; */ margin: 0 auto; /* padding: 1em; */ width: 300px; scroll-snap-align: center; scroll-padding-top: 300px; display: flex; flex-flow: column; justify-content: center; text-align: center; font-size: 4em; } .links { display: flex; justify-content: space-between; flex-direction: column; /* padding: 0 1em; */ } .links h2 { font-family: 'Fredoka One'; font-weight: 100; padding: 0; } .issue-list { width: fit-content; margin-left: auto; font-family: 'Arial'; font-size: 18px; z-index: 1; } .issue-list p{ margin: 0; } .issue-list p a { cursor: pointer; text-decoration: none; color: black; } .info { position: absolute; bottom: 0; /* padding: 0 1em; */ } .info p { font-size: 19px; font-weight: bold; font-family: 'Chivo Mono'; }
JavaScript(新增监听逻辑)
const gra = function (min, max) { return Math.random() * (max - min) + min; }; const init = function () { let items = document.querySelectorAll(".scroller div"); for (let i = 0; i < items.length; i++) { items[i].style.minHeight = gra(100, 100) + "vh"; const randomColor = Math.floor(Math.random() * 16777215).toString(16); const colorHex = "#" + randomColor; items[i].style.backgroundColor = colorHex; // 把颜色存入自定义属性,避免后续格式转换 items[i].dataset.color = colorHex; } // 初始化滚动吸附监听 setupScrollSnapObserver(); }; const setupScrollSnapObserver = function() { const scrollContainer = document.getElementById('scroll-box'); const books = document.querySelectorAll('.book'); // 配置观察规则:根元素为滚动容器,观察区域缩至视口中线 const observerOptions = { root: scrollContainer, rootMargin: "-50% 0px -50% 0px", threshold: 1.0 }; // 交叉状态变化时的回调 const observerCallback = (entries) => { entries.forEach(entry => { if (entry.isIntersecting) { // 更新页面背景色为当前吸附元素的颜色 document.getElementById('background').style.backgroundColor = entry.target.dataset.color; } }); }; // 创建Observer并监听所有.book元素 const observer = new IntersectionObserver(observerCallback, observerOptions); books.forEach(book => observer.observe(book)); }; init();
关键细节说明
rootMargin: "-50% 0px -50% 0px":将观察区域限制在视口的水平中线位置,只有当元素中心与中线重合(即scroll-snap到中心)时,才会触发交叉状态threshold: 1.0:确保元素完全进入观察区域时才触发回调,避免滚动过程中频繁切换颜色dataset.color:提前存储hex格式的颜色,避免直接从style.backgroundColor获取到rgb格式的颜色,减少格式转换的麻烦
内容的提问来源于stack exchange,提问作者TeDi
相关产品推荐
相关产品推荐

