如何在滚动经过图片时将sticky侧边栏文本颜色从黑色改为白色
实现思路
核心用IntersectionObserver API检测sticky文本和图片的重叠状态,性能远高于高频监听scroll事件,适配任意垂直滚动场景。
第一步:调整基础CSS
先把侧边栏文本调整为sticky定位,同时保留原有类的样式:
/* 新增sticky侧边栏容器样式,可根据实际布局调整位置 */ .sidebar { position: sticky; top: 20px; left: 5%; z-index: 1; /* 低于图片容器的z-index:2,重叠时图片在上 */ width: fit-content; } .section-title { margin: 0; font-size: 64px; white-space: nowrap; color: #000; /* 默认黑色 */ transition: color 0.2s ease; /* 加过渡效果更自然 */ } .section-title.on-dark { color: #fff; /* 重叠时切换为白色 */ } .image-container { padding-bottom: 100%; background: black; position: relative; overflow: hidden; z-index: 2; background-size: cover; background-position: center; margin-bottom: 200px; /* 图片之间留间距,方便观察效果 */ }
第二步:添加重叠检测JS逻辑
不需要修改原有视差动画的代码,新增以下逻辑即可:
const stickyText = document.querySelector('.section-title'); const imageContainers = document.querySelectorAll('.image-container'); // 创建重叠检测器 const observer = new IntersectionObserver((entries) => { entries.forEach(entry => { // 图片和sticky文本进入重叠状态时加类,离开时移除 entry.isIntersecting ? stickyText.classList.add('on-dark') : stickyText.classList.remove('on-dark'); }); }, { root: null, // 以视口为检测基准 threshold: 0, // 只要有1px重叠就触发 rootMargin: "0px 0px 0px -10%" /* 调整该值控制触发时机,负值表示从左侧内缩检测范围,匹配侧边栏位置 */ }); // 给所有图片容器绑定监听 imageContainers.forEach(img => observer.observe(img));
完整可运行代码
可直接复制测试效果:
<!DOCTYPE html> <html lang="zh-CN"> <head> <meta charset="UTF-8"> <title>滚动文本变色示例</title> <style> * { margin: 0; padding: 0; box-sizing: border-box; } body { min-height: 3000px; font-family: 'Montserrat', sans-serif; } .sidebar { position: sticky; top: 20px; left: 5%; z-index: 1; width: fit-content; } .outer-container { max-width: 600px; margin: 0 25% 0 auto; width: 60%; padding: 200px 0px; position: relative; } .image-container { padding-bottom: 100%; position: relative; overflow: hidden; z-index: 2; background-size: cover; background-position: center; margin-bottom: 200px; background-image: url('https://images.unsplash.com/photo-1570528812862-9984124e7e22?ixlib=rb-1.2.1&q=85&fm=jpg&crop=entropy&cs=srgb&ixid=eyJhcHBfaWQiOjE0NTg5fQ'); } .section-title { font-size: 64px; white-space: nowrap; color: #000; transition: color 0.2s ease; } .section-title.on-dark { color: #fff; } .section-title span { position: relative; display: block; } </style> </head> <body> <!-- 侧边栏sticky文本 --> <div class="sidebar"> <h2 class="section-title"> <span class="paralax-title"> Live The Adventure </span> </h2> </div> <!-- 内容区图片 --> <div class="outer-container"> <div class="image-container"></div> <div class="image-container" style="background-image: url('https://images.unsplash.com/photo-1506905925346-21bda4d32df4?ixlib=rb-1.2.1&q=85&fm=jpg&crop=entropy&cs=srgb')"></div> <div class="image-container" style="background-image: url('https://images.unsplash.com/photo-1551632811-561732d1e306?ixlib=rb-1.2.1&q=85&fm=jpg&crop=entropy&cs=srgb')"></div> </div> <script> // 原有视差动画代码,不需要可直接删除 let didScroll = false; const paralaxTitles = document.querySelectorAll('.paralax-title'); const scrollInProgress = () => { didScroll = true } const raf = () => { if(didScroll) { paralaxTitles.forEach((element, index) => { element.style.transform = "translateX("+ window.scrollY / 10 + "%)" }) didScroll = false; } requestAnimationFrame(raf); } requestAnimationFrame(raf); window.addEventListener('scroll', scrollInProgress) // 重叠检测逻辑 const stickyText = document.querySelector('.section-title'); const imageContainers = document.querySelectorAll('.image-container'); const observer = new IntersectionObserver((entries) => { entries.forEach(entry => { entry.isIntersecting ? stickyText.classList.add('on-dark') : stickyText.classList.remove('on-dark'); }); }, { root: null, threshold: 0, rootMargin: "0px 0px 0px -10%" }); imageContainers.forEach(img => observer.observe(img)); </script> </body> </html>
参数调整说明
- 不需要横向视差效果的话,直接删除对应的JS代码和
.paralax-title相关样式即可 - 修改
rootMargin的最后一个值可以调整触发变色的时机,值越小(负的越多),需要文本进入图片区域更多才会触发变色 - 侧边栏在右侧的话,把
rootMargin的最后一个值改成正的即可适配。
内容的提问来源于stack exchange,提问作者Josef Lundström
相关产品推荐
相关产品推荐

