使用CSS与JavaScript实现图片滚动至导航栏时停止上移效果
图片滚动贴导航栏停驻实现方案
核心逻辑:滚动时判断图片元素与固定导航栏的位置关系,当图片顶部触碰到导航栏底部时,切换为固定定位贴在导航栏下方;回滚到图片初始位置以上时,恢复原有定位,不影响向下滚动的正常浏览,同时保留原有的滚动缩放宽度效果。
1. 调整CSS样式
给目标图片容器新增吸顶状态的样式,处理固定定位后的水平居中问题,在原有styles.css基础上修改:
.mainSec { width: 100%; display: flex; justify-content: center; } #animatedDiv { background: url("https://media.tenor.com/images/34b16b199449136a845ea0300ff2cef3/raw") no-repeat; min-height: 200vh; width: 50%; position: absolute; margin-top: 20%; /* 可选:给宽度变化加微量过渡,避免快速滚动时卡顿跳变 */ transition: width 0.1s linear; } /* 新增:吸顶状态样式 */ #animatedDiv.stuck { position: fixed; top: 10vh; /* 与导航栏高度完全一致,刚好贴在导航栏下沿 */ margin-top: 0; left: 50%; transform: translateX(-50%); /* 固定定位后手动保持水平居中,匹配原有flex居中效果 */ } #secondPage { background: url("https://www.downloadclipart.net/large/doraemon-png-free-download.png") no-repeat; display: block; width: 50%; } body { margin: 0; padding: 0; box-sizing: border-box; font-family: sans-serif; } nav { position: fixed; height: 10vh; background-color: rgb(12, 77, 151); display: flex; align-items: center; width: 100%; /* 给导航栏加z-index,避免固定后被其他元素遮挡 */ z-index: 10; } /* 以下原有导航栏、logo、菜单样式全部保留不变 */ nav .logo a { color: white; font-size: 1.5rem; text-decoration: none; display: flex; text-align: center; margin: 0px 10px; } nav .nav-links { list-style: none; margin-left: auto; } .nav-links li { display: inline-block; } .nav-links .active { background-color: black; border: 2px solid black; border-radius: 10px; } nav .nav-links li a { color: white; text-decoration: none; font-size: 1rem; font-weight: 500; padding: 0px 10px; } @media screen and (max-width: 768px) { nav { position: relative; display: block; } /* 新增:移动端导航栏随页面滚动,禁用吸顶效果 */ #animatedDiv.stuck { position: absolute; top: auto; left: auto; transform: none; margin-top: 20%; } /* 以下原有移动端样式全部保留不变 */ .logo { height: 10vh; display: flex; align-items: center; } .logo a { text-align: center; } nav .menuIcon { position: absolute; cursor: pointer; top: 30%; right: 5%; } nav .menuIcon .line { width: 30px; margin: 5px 0px; height: 3px; background-color: white; position: relative; } nav .menuIcon .line:nth-child(1).open { transform: rotate(45deg); width: 40px; height: 5px; left: 0px; top: 16px; transition: all 1s ease; } nav .menuIcon .line:nth-child(2).open { opacity: 0; } nav .menuIcon .line:nth-child(3).open { transform: rotate(-45deg); width: 40px; height: 5px; transition: all 1s ease; } nav .nav-links { margin-top: -10px; padding: 0px; height: 90vh; width: 100%; background-color: rgb(12, 77, 151); display: flex; align-items: center; flex-direction: column; clip-path: circle(50px at 90% -10%); -webkit-clip-path: circle(50px at 90% -10%); transition: all 1s ease-out; } .nav-links li { margin: 40px 0px; } nav .nav-links.open { clip-path: circle(1000px at 90% -10%); -webkit-clip-path: circle(1000px at 90% -10%); } .nav-links li { opacity: 0; } .nav-links li a { font-size: 25px; } .nav-links li:nth-child(1) { transition: all 0.5s ease 0.2s; } .nav-links li:nth-child(2) { transition: all 0.5s ease 0.4s; } .nav-links li:nth-child(3) { transition: all 0.5s ease 0.6s; } .nav-links li:nth-child(4) { transition: all 0.5s ease 0.8s; } li.fade { opacity: 1; } .logo.close { visibility: hidden; } }
2. 修改JS滚动逻辑
在原有宽度计算逻辑基础上,新增位置判断,控制吸顶类的添加移除,原有菜单交互代码完全不需要改动,修改后的index.js如下:
var aDiv = document.getElementById("animatedDiv"); // 提前计算固定值,避免每次滚动重复计算引发性能损耗 const navHeight = window.innerHeight * 0.1; // 对应导航栏10vh的高度 const initialDivOffsetTop = aDiv.offsetTop; // 图片容器初始状态距离页面顶部的距离 function onScroll() { var scrollVal = window.pageYOffset; // 保留原有的宽度缩放逻辑 const targetWidth = 50 - (scrollVal * 100) / 1500; aDiv.style.width = targetWidth <= 10 ? "10%" : targetWidth + "%"; // 新增吸顶判断 if (scrollVal + navHeight >= initialDivOffsetTop) { // 图片顶部触碰到导航栏底部,添加吸顶类 aDiv.classList.add("stuck"); } else { // 回滚到图片初始位置以上,移除吸顶类恢复原状态 aDiv.classList.remove("stuck"); } } window.addEventListener( "scroll", function () { requestAnimationFrame(onScroll); }, false ); // 以下原有菜单交互代码完全保留,不需要修改 const menuIcon = document.querySelector(".menuIcon"); const menuIcons = document.querySelectorAll(".menuIcon .line"); const navLinks = document.querySelector(".nav-links"); const items = document.querySelectorAll(".nav-links li"); const logo = document.querySelector(".logo"); menuIcon.addEventListener("click", () => { navLinks.classList.toggle("open"); logo.classList.toggle("close"); items.forEach((item) => { item.classList.toggle("fade"); }); menuIcons.forEach((Icon) => { Icon.classList.toggle("open"); }); }); const menu = document.querySelector(".nav-links"); const menuItems = document.querySelectorAll(".nav-links li"); menuItems.forEach((item) => { item.addEventListener("click", function () { menu.querySelector(".active").classList.remove("active"); item.classList.add("active"); }); });
补充说明
- 如果后续调整导航栏高度,同步修改CSS中
#animatedDiv.stuck的top值和JS中navHeight的计算逻辑,保持两个值一致即可,不会出现缝隙或者图片被导航栏遮挡的问题。 - 导航栏的
z-index:10可根据实际项目层级调整数值,避免固定定位的图片层级过高盖住导航栏。 - 方案完全兼容原有宽度缩放动画、移动端汉堡菜单交互,不会产生冲突。
内容的提问来源于stack exchange,提问作者TechDev
相关产品推荐
相关产品推荐

