滚动位置切换图片效果实现求助:复刻Calendly页面动画
问题:复刻Calendly滚动切换图片板块失败
我尝试复刻Calendly网站中的「分享你的Calendly可用时间给他人」板块,需求动画效果为:左侧标题与内容区域可滚动,滚动时当前图片淡出并切换为下一张图片。我制作了一个示例,但无法正常实现效果。
原代码
HTML
<script src="https://cdnjs.cloudflare.com/ajax/libs/ScrollMagic/2.0.8/ScrollMagic.min.js"></script> <div class="container"> <div class="wrapper"> <div class="text-column"> <h1>Share your Calendly availability with others</h1> <p> Grow your business with scheduling automation. Simply email, text, or add your Calendly availability to your website – and watch prospects and recruits book high-value meetings with you.</p> </div> <div class="image-column-inner"> <div class="image-column"> <img src="https://images.ctfassets.net/k0lk9kiuza3o/7mkknkKmPsEGwaB5mdt60t/33d742a897f87e8f6f5e11df85659960/Calendly-Email-Embed.png?w=1140&h=930&q=50&fm=webp" alt="image"> </div> </div> </div> <div class="wrapper"> <div class="text-column"> <h1>Schedule as a team </h1> <p> Calendly adapts to both you and your team's scheduling preferences. Co-host a client call with a colleague, email reminders and follow-ups, and integrate everything with your preferred software tools.</p> </div> <div class="image-column-inner"> <div class="image-column"> <img src="https://images.ctfassets.net/k0lk9kiuza3o/7mkknkKmPsEGwaB5mdt60t/33d742a897f87e8f6f5e11df85659960/Calendly-Email-Embed.png?w=1140&h=930&q=50&fm=webp" alt="image"> </div> </div> </div> <div class="wrapper"> <div class="text-column"> <h1>Hit your number</h1> <p> High-value meetings are the lifeblood of your business. Increase revenue, retain customers, and land recruits with the #1 scheduling automation platform. </p> </div> <div class="image-column-inner"> <div class="image-column"> <img src="https://images.ctfassets.net/k0lk9kiuza3o/7mkknkKmPsEGwaB5mdt60t/33d742a897f87e8f6f5e11df85659960/Calendly-Email-Embed.png?w=1140&h=930&q=50&fm=webp" alt="image"> </div> </div> </div> </div>
CSS
.container { display: flex; flex-direction: column; max-width: 1280px; margin: 0 auto; visibility: visible } .wrapper { display: flex; flex-direction: row; justify-content: center; align-items: center; height: 70vh; } .wrapper { visibility: hidden; } .wrapper.in-view { visibility: visible; } .text-column { width: 50%; padding: 20px; box-sizing: border-box; } .image-column-inner { width: 50%; position: sticky; top: 0; right: 0; top: calc(50% - 35vh); height: 70vh; } .image-column { width: 100%; display: flex; -webkit-box-align: center; align-items: center; -webkit-box-pack: center; justify-content: center; height: 100%; max-height: 100vh; position: absolute; z-index: 9; } img { width: 100%; height: 100%; display: block; transition: opacity 0.5s; }
JavaScript
var wrappers = document.querySelectorAll(".wrapper"); function checkInView() { wrappers.forEach(function(wrapper) { var bounds = wrapper.getBoundingClientRect(); if (bounds.top < window.innerHeight && bounds.bottom > 0) { wrapper.classList.add("in-view"); } else { wrapper.classList.remove("in-view"); } }); } window.addEventListener("load", function() { var imageColumn = wrappers[0].querySelector(".image-column"); imageColumn.style.opacity = 1; }); window.addEventListener("scroll", function() { checkInView(); wrappers.forEach(function(wrapper) { var scrollPos = window.scrollY; var wrapperPos = wrapper.offsetTop; var wrapperHeight = wrapper.offsetHeight; var imageColumn = wrapper.querySelector(".image-column"); if (scrollPos > wrapperPos && scrollPos < wrapperPos + wrapperHeight) { imageColumn.style.transform = "translateY(" + (scrollPos - wrapperPos) + "px)"; imageColumn.classList.add("fade-out"); } else { imageColumn.classList.remove("fade-out"); imageColumn.classList.add("fade-in"); } }); });
问题分析
- 图片容器结构错误:每个
wrapper都包含独立的image-column-inner,导致图片无法固定在右侧统一切换,而是随每个区块滚动。 - 淡入淡出样式缺失:仅定义了
transition,但未给fade-in、fade-out类添加opacity属性,导致动画无效果。 - 滚动逻辑混乱:同时处理所有
wrapper的图片变换,无法实现当前区块对应图片的精准切换。
修复方案
核心调整
- 将图片容器移出
wrapper,改为全局固定在右侧,统一管理所有图片的显示/隐藏。 - 定义完整的淡入淡出CSS类。
- 优化滚动监听逻辑,仅激活当前视口内的
wrapper对应的图片。
修复后的完整代码
HTML
<div class="container"> <!-- 全局固定图片容器 --> <div class="fixed-image-container"> <div class="image-column active"> <img src="https://images.ctfassets.net/k0lk9kiuza3o/7mkknkKmPsEGwaB5mdt60t/33d742a897f87e8f6f5e11df85659960/Calendly-Email-Embed.png?w=1140&h=930&q=50&fm=webp" alt="分享可用时间"> </div> <div class="image-column"> <img src="https://images.ctfassets.net/k0lk9kiuza3o/5Z7XU7L3Rny8A5n1y1e1L9/6a498f080f2a41a97a4a4f7d40a8a11a/Calendly-Team-Scheduling.png?w=1140&h=930&q=50&fm=webp" alt="团队日程"> </div> <div class="image-column"> <img src="https://images.ctfassets.net/k0lk9kiuza3o/4Z1Z1Z1Z1Z1Z1Z1Z1Z1Z1/1234567890abcdef1234567890abcdef/Calendly-Revenue-Growth.png?w=1140&h=930&q=50&fm=webp" alt="业绩增长"> </div> </div> <!-- 文本区块 --> <div class="wrapper"> <div class="text-column"> <h1>分享你的Calendly可用时间给他人</h1> <p> 用日程自动化拓展业务。只需通过邮件、短信分享,或者将你的Calendly可用时间添加到网站——就能看到潜在客户和候选人预约高价值会议。 </p> </div> </div> <div class="wrapper"> <div class="text-column"> <h1>团队协作日程</h1> <p> Calendly适配你和团队的日程偏好。与同事共同主持客户会议、发送提醒和跟进邮件,并与你偏好的软件工具深度集成。 </p> </div> </div> <div class="wrapper"> <div class="text-column"> <h1>达成业绩目标</h1> <p> 高价值会议是业务的生命线。借助全球排名第一的日程自动化平台,提升营收、留存客户、招募人才。 </p> </div> </div> </div>
CSS
* { margin: 0; padding: 0; box-sizing: border-box; } body { overflow-x: hidden; } .container { max-width: 1280px; margin: 0 auto; position: relative; } .wrapper { display: flex; justify-content: flex-start; align-items: center; height: 100vh; padding-left: 20px; } .text-column { width: 50%; } .text-column h1 { font-size: 2.5rem; margin-bottom: 1.5rem; } .text-column p { font-size: 1.2rem; line-height: 1.6; color: #555; } /* 固定图片容器 */ .fixed-image-container { position: fixed; top: 50%; right: calc((100vw - 1280px) / 2 + 20px); transform: translateY(-50%); width: 45%; height: 80vh; z-index: 10; } .image-column { position: absolute; top: 0; left: 0; width: 100%; height: 100%; display: flex; align-items: center; justify-content: center; opacity: 0; transition: opacity 0.6s ease-in-out; } .image-column.active { opacity: 1; } .image-column img { width: 100%; height: 100%; object-fit: contain; }
JavaScript
const wrappers = document.querySelectorAll('.wrapper'); const imageColumns = document.querySelectorAll('.image-column'); function updateActiveImage() { let activeIndex = 0; wrappers.forEach((wrapper, index) => { const bounds = wrapper.getBoundingClientRect(); // 判断当前wrapper是否处于视口中心区域 if (bounds.top <= window.innerHeight / 2 && bounds.bottom >= window.innerHeight / 2) { activeIndex = index; } }); // 切换图片激活状态 imageColumns.forEach((imgCol, index) => { imgCol.classList.toggle('active', index === activeIndex); }); } // 初始加载和滚动时更新 window.addEventListener('load', updateActiveImage); window.addEventListener('scroll', updateActiveImage); window.addEventListener('resize', updateActiveImage);
效果说明
- 左侧文本区块随页面滚动,每个区块占满一屏高度。
- 右侧图片容器固定在视口右侧,当滚动到对应文本区块时,图片平滑淡入切换。
- 适配窗口大小变化,保证布局和动画正常。
内容的提问来源于stack exchange,提问作者Mitchell_K
相关产品推荐
相关产品推荐

