鼠标悬停/移出缩放切换整改前后图片功能异常,求解决方案
城市环境整改照片切换动画问题解决
需求说明
开发城市环境问题(涂鸦、坑洼等)整改服务的展示功能:
- 鼠标悬停时显示整改前照片
- 鼠标移出时恢复显示整改后照片
- 两次切换均需带有缩放动画
现有代码
index.php
<img alt='<?=$problem->name?>' class='img-fluid' src='uploads/<?=$problem->photoAfter?>' data-before='uploads/<?=$problem->photoBefore?>' data-after='uploads/<?=$problem->photoAfter?>' onMouseOver='hover(this)' onMouseOut='back(this)'> <script> function hover(el){ el.src = el.dataset.before; el.classList.remove("after"); el.classList.add("before"); } function back(el){ el.src = el.dataset.after; el.classList.remove("before"); el.classList.add("after"); } </script>
site.css
.before { animation: scaling 1500ms; } .after { animation: scaling 1500ms; } @keyframes scaling { 0% { transform: scale(0); } 100% { transform: scale(1);} }
当前问题
- 鼠标悬停时动画仅生效一次
- 悬停时先执行缩放动画,再加载显示整改前图片
- 鼠标移出时无动画,直接切换回整改后图片
调整方案
核心思路
用双层图片容器实现切换(避免直接替换src导致的加载延迟和动画不同步),通过CSS transition 控制缩放动画,无需额外JS事件绑定,更稳定可靠。
修改后代码
index.php
<div class="problem-photo-container"> <!-- 整改前照片:默认缩放隐藏 --> <img alt='<?=$problem->name?>(整改前)' class='img-fluid problem-photo problem-photo-before' src='uploads/<?=$problem->photoBefore?>' > <!-- 整改后照片:默认显示 --> <img alt='<?=$problem->name?>(整改后)' class='img-fluid problem-photo problem-photo-after' src='uploads/<?=$problem->photoAfter?>' > </div>
site.css
/* 容器设置相对定位,让两张照片重叠 */ .problem-photo-container { position: relative; /* 自动适配图片宽度 */ width: fit-content; height: fit-content; overflow: hidden; } .problem-photo { position: absolute; top: 0; left: 0; /* 用transition实现平滑缩放动画,时长可调整 */ transition: transform 0.8s cubic-bezier(0.4, 0, 0.2, 1); } /* 默认状态:整改后照片显示,整改前照片缩小隐藏 */ .problem-photo-after { transform: scale(1); z-index: 1; } .problem-photo-before { transform: scale(0); z-index: 2; } /* 悬停状态:整改后照片缩小隐藏,整改前照片放大显示 */ .problem-photo-container:hover .problem-photo-after { transform: scale(0); } .problem-photo-container:hover .problem-photo-before { transform: scale(1); }
方案说明
- 双层图片布局:两张照片通过绝对定位重叠,避免替换
src时的加载延迟,确保动画和图片切换同步。 - CSS Transition替代Animation:
transition会在元素状态变化时自动触发,解决了原animation仅执行一次的问题,每次悬停/移出都会重新播放动画。 - 层级控制:通过
z-index确保整改前照片悬停时在最上层,整改后照片默认显示在最上层。 - 动画平滑性:使用
cubic-bezier曲线可以让动画更自然,时长可根据需求调整(示例中为0.8秒)。
可选优化(若需保留JS逻辑)
如果一定要用单图片切换的方式,需要解决动画触发和图片加载顺序问题:
function hover(el) { // 先添加动画类触发缩放缩小 el.classList.add("scale-out"); // 等待动画结束后再切换图片 setTimeout(() => { el.src = el.dataset.before; // 强制重绘确保动画重新触发 el.offsetWidth; el.classList.remove("scale-out"); el.classList.add("scale-in"); }, 800); // 时长和CSS动画一致 } function back(el) { el.classList.add("scale-out"); setTimeout(() => { el.src = el.dataset.after; el.offsetWidth; el.classList.remove("scale-out"); el.classList.add("scale-in"); }, 800); }
对应的CSS:
.scale-in { animation: scale-in 0.8s forwards; } .scale-out { animation: scale-out 0.8s forwards; } @keyframes scale-in { from { transform: scale(0); } to { transform: scale(1); } } @keyframes scale-out { from { transform: scale(1); } to { transform: scale(0); } }
但这种方式不如双层图片方案稳定,容易出现加载延迟导致的动画不同步问题。
内容的提问来源于stack exchange,提问作者Kifsif
相关产品推荐
相关产品推荐

