实现图片到内容的Zoom in过渡效果及滚动问题修复求助
图片到内容的Zoom In过渡效果实现方案
问题说明
我正在学习原生JavaScript,需完成一个点击按钮触发图片到内容的Zoom in过渡效果项目,需求如下:
- 页面初始展示占满浏览器视口的图片+按钮(intro容器)
- 点击按钮后,先延迟1-2秒,再进行平滑的Zoom in过渡(效果类似穿过图片中的门进入场景)
- 过渡完成后显示网站实际内容(trailer容器)
当前代码存在两个问题:
- 过渡效果不符合预期
- 因body设置
overflow:hidden、trailer-container设置position:fixed,导致页面无法滚动
修复方案
1. 优化Zoom In过渡效果
- 给intro容器添加
overflow:hidden,防止图片缩放溢出 - 动态设置缩放原点为按钮位置(视觉焦点),用
transform-origin锚定按钮中心,模拟"穿过门"的沉浸感 - 用
setTimeout实现1.5秒延迟后执行缩放动画 - 缩放完成后隐藏intro容器,避免遮挡主体内容
2. 恢复页面滚动功能
- 移除body默认的
overflow:hidden,仅在intro显示时临时添加该属性,过渡完成后移除 - 将trailer-container的
position:fixed改为position:relative,回归正常文档流 - 调整trailer-container布局,用常规方法适配内容,移除
transform: translate(-50%, -50%)
修改后的完整代码
HTML
<body> <div class="intro-container"> <img src="https://www.hoganbakery.com.my/wp-content/uploads/2019/09/lion-office-tower.jpg" alt="场景图片"> <button class="btn">点击进入选择页面</button> </div> <div class="trailer-container active"> <form action="" name="myForm"> <section class="first-section"> <h3>选择商品:</h3> <div> <input type="number" name="bread" id="bread" placeholder="数量?"> <label for="bread">面包</label> </div> <div> <input type="number" name="croissant" id="croissant" placeholder="数量?"> <label for="croissant">可颂</label> </div> </section> <section class="third-section"> <h3>您有账号吗?</h3> <div> <input type="radio" name="account" id="yes"> <label for="yes">我有账号</label> </div> <div> <input type="radio" name="account" id="no"> <label for="no">我没有账号</label> </div> </section> <section class="commands"> <input type="button" id="submit" value="提交"> </section> </form> </div> </body>
CSS
body { margin: 0; /* 初始不隐藏滚动,仅intro显示时添加类控制 */ } body.intro-active { overflow: hidden; height: 100vh; } .intro-container { position: fixed; top: 0; left: 0; width: 100%; height: 100vh; overflow: hidden; z-index: 10; transition: opacity 0.5s ease-out; } .intro-container img { width: 100%; height: 100%; object-fit: cover; object-position: center; transition: transform 2s cubic-bezier(0.25, 0.46, 0.45, 0.94); } .intro-container.disappear img { transform: scale(5); } .intro-container.hidden { opacity: 0; pointer-events: none; } button.btn { position: absolute; left: 50%; top: 50%; transform: translate(-50%, -50%); padding: 15px 20px; background: #2a78d7; font-size: 18px; font-weight: 700; border-radius: 12px; cursor: pointer; color: white; text-transform: uppercase; border: 3px solid #20323e; text-shadow: 1px 1px 4px black; z-index: 11; } .trailer-container { position: relative; width: 100%; min-height: 100vh; display: flex; flex-direction: column; justify-content: start; align-items: center; background-color: rgb(228, 223, 224); padding: 2rem 0; opacity: 0; transition: opacity 0.5s ease-in; } .trailer-container.active { opacity: 1; } form { width: 90%; max-width: 600px; } section { margin-bottom: 2rem; }
JavaScript
const btnEl = document.querySelector(".btn"); const trailerContainerEl = document.querySelector(".trailer-container"); const introContainerEl = document.querySelector(".intro-container"); const introImgEl = introContainerEl.querySelector("img"); const bodyEl = document.body; // 动态设置缩放原点为按钮中心位置 const btnRect = btnEl.getBoundingClientRect(); const originX = btnRect.left + btnRect.width / 2; const originY = btnRect.top + btnRect.height / 2; introImgEl.style.transformOrigin = `${originX}px ${originY}px`; btnEl.addEventListener("click", () => { // 临时隐藏页面滚动 bodyEl.classList.add("intro-active"); // 1.5秒延迟后执行缩放动画 setTimeout(() => { introContainerEl.classList.add("disappear"); // 缩放动画完成后,隐藏intro、显示内容并恢复滚动 setTimeout(() => { introContainerEl.classList.add("hidden"); trailerContainerEl.classList.remove("active"); bodyEl.classList.remove("intro-active"); }, 2000); }, 1500); });
内容的提问来源于stack exchange,提问作者Vlada Ristic
相关产品推荐
相关产品推荐

