如何实现图片从固定尺寸到全屏的流畅动画并兼容Safari?
优化方案
核心优化逻辑是将所有触发浏览器重排的属性(max-width、top)替换为仅触发合成层渲染的transform属性,彻底解决动画卡顿问题;同时添加Safari专属兼容配置,修复transform过渡失效问题,全程保留原有交互逻辑。
修改后完整代码
HTML(无改动)
<div class="wrapper"> <div class="image-wrapper" id="image-wrapper"> <img src="https://via.placeholder.com/3000x2857.webp" alt=""> <div class="image-overlay" id="overlay"></div> </div> </div>
CSS
body { min-height: 100vh; overflow-x: hidden; margin: 0; } img { width: 100%; height: auto; display: block; } .wrapper { width: 100vw; min-height: 100vh; height: 100%; position: relative; } .image-wrapper { position: absolute; left: 50%; top: 50%; transform: translate(-50%, -50%) scale(1); max-width: 300px; width: 100%; /* 仅过渡transform属性,无重排开销 */ -webkit-transition: transform .8s ease; transition: transform .8s ease; /* Safari兼容配置,提前触发GPU加速 */ will-change: transform; -webkit-backface-visibility: hidden; backface-visibility: hidden; -webkit-perspective: 1000; perspective: 1000; } .image-wrapper.active { max-width: 100vw; top: 0; transform: translate(-50%, 0) scale(var(--scale-rate, 3.33)); } .image-overlay { position: absolute; top: 0; left: 0; width: 100%; height: 100%; background-color: transparent; opacity: .7; transition: background-color .3s ease; cursor: pointer; } .image-overlay:hover { background-color: #000000; }
JavaScript
const imageWrapper = document.getElementById("image-wrapper"); const overlay = document.getElementById("overlay"); // 动态计算缩放比例,适配不同窗口尺寸 function updateScaleRate() { const rate = window.innerWidth / 300; imageWrapper.style.setProperty('--scale-rate', rate.toFixed(2)); } updateScaleRate(); window.addEventListener('resize', updateScaleRate); // 切换逻辑 function toggleImageWrapper() { if (imageWrapper.classList.contains('active')) { // 缩小前重置布局属性,保证动画衔接平滑 imageWrapper.style.maxWidth = '300px'; imageWrapper.style.top = '50%'; requestAnimationFrame(() => { imageWrapper.classList.remove('active'); }) } else { imageWrapper.classList.add('active'); } } overlay.addEventListener("click", () => { toggleImageWrapper(); }) // 动画结束后修正布局,避免缩放导致的交互区域异常 imageWrapper.addEventListener('transitionend', (e) => { if (e.propertyName !== 'transform') return; if (imageWrapper.classList.contains('active')) { imageWrapper.style.transform = 'translate(-50%, 0) scale(1)'; } else { imageWrapper.style.transform = 'translate(-50%, -50%) scale(1)'; } })
内容的提问来源于stack exchange,提问作者Ghetto Jezuz
相关产品推荐
相关产品推荐

