检测元素处于视口中央时动态修改透明度的实现方案
滚动视口居中动态修改元素透明度实现方案
实现逻辑
硬编码scrollY阈值的方案只能适配固定位置的单个元素,通用实现不需要写死任何像素值,核心计算逻辑如下:
- 视口垂直中心坐标固定为
window.innerHeight / 2 - 每个区块的垂直中心坐标可通过
getBoundingClientRect().top + 元素自身高度 / 2计算得到 - 对比两个中心的距离:距离为0(区块刚好在视口正中央)时透明度为1,距离超过设定阈值时透明度回到初始0.2,中间区间做线性插值实现平滑过渡
- 遍历所有目标区块统一计算,支持任意数量的区块自动适配
完整实现代码
CSS 部分
.box { height: 100vh; display: flex; align-items: center; justify-content: center; } .grid { display: grid; grid-gap: 10px; } .block { opacity: 0.2; /* 可选:加过渡让透明度变化更顺滑,删除则为硬切换效果 */ transition: opacity 0.1s linear; }
JavaScript 部分
// 触发阈值:区块中心距离视口中心超过这个值时,透明度回到0.2,可按需调整 const VISIBLE_THRESHOLD = 150; // 获取所有需要做效果的区块,无需单独绑定id const blocks = document.querySelectorAll('.block'); const updateBlockOpacity = () => { const viewportCenterY = window.innerHeight / 2; blocks.forEach(block => { const rect = block.getBoundingClientRect(); const blockCenterY = rect.top + block.offsetHeight / 2; const distanceToCenter = Math.abs(viewportCenterY - blockCenterY); let targetOpacity; if (distanceToCenter >= VISIBLE_THRESHOLD) { targetOpacity = 0.2; } else { // 线性计算当前透明度:距离越近越接近1 targetOpacity = 1 - (distanceToCenter / VISIBLE_THRESHOLD) * 0.8; } block.style.opacity = targetOpacity; }); }; // 页面初始化时执行一次,修正首屏状态 updateBlockOpacity(); // 监听滚动,加passive参数提升滚动性能 window.addEventListener('scroll', updateBlockOpacity, { passive: true }); // 监听窗口尺寸变化,自动重新计算位置 window.addEventListener('resize', updateBlockOpacity);
HTML 部分
原有结构无需大改,去掉第一个区块硬编码的isActive类即可,JS会自动初始化所有区块的状态:
<div> <div class="box"> <span>Welcome</span> </div> <div id="container" class="grid"> <span class="block"> Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet. Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet. </span> <span class="block"> Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet. Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet. </span> <span class="block"> Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet. Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet. </span> </div> <div class="box"> <span>More elements</span> </div> </div>
参数调整说明
- 修改
VISIBLE_THRESHOLD数值可以调整触发范围:数值越大,区块距离视口中心更远时就会开始逐渐变清晰;数值越小,需要更精准对准中心才会达到完全不透明的效果 - 如果不需要平滑过渡,删除CSS里的
transition属性即可回到硬切换的效果,也可以把JS里的透明度计算改成判断距离小于某个阈值时直接设为1,否则设为0.2
内容的提问来源于stack exchange,提问作者Tobias90
相关产品推荐
相关产品推荐

