You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何让垂直图片视差动画更流畅?

如何让垂直图片视差动画更流畅?

我明白你现在遇到的问题啦——鼠标刚移上去图片会突然跳动,加了过渡又跟不上鼠标移动的速度,确实挺影响体验的。咱们一步步调整代码,把这个视差效果改得全程丝滑:

先说说现有代码的核心问题

  1. 过渡逻辑冲突:你在mouseenter、mousemove、mouseleave里反复修改transition属性,导致刚进入时的第一个位置变化是瞬间的,直接跳帧;
  2. 视差计算有误:当前的位置比例计算逻辑不对,会导致图片移动范围不符合预期;
  3. 未做性能优化:鼠标移动事件触发极频繁,直接修改样式容易出现卡顿,跟不上鼠标速度。

优化后的完整代码

1. CSS 部分(调整过渡和优化动画)

#display-grid{
    display: grid;
    width: 80%;
    gap: 1rem;
    grid-template-columns: repeat(auto-fit, minmax(24%, 1fr));
}

.cell{
    border: 1px solid #EEEEEE;
    border-radius: 1rem;
    width: 100%;
    overflow: hidden;
    position: relative;
    border-radius: 12px;
    aspect-ratio: 1 / 1.2;
}

.cell .image-container{
    width: 100%;
    height: 90%;
    position: relative;
    aspect-ratio: 1 / 1;
    border-radius: 1rem;
    overflow: hidden;
    cursor: pointer; /* 加个鼠标样式更友好 */
}

.cell img {
    width: 100%;
    height: auto;
    object-fit: cover;
    object-position: top;
    border-radius: 1rem;
    will-change: transform; /* 告诉浏览器提前优化这个属性的动画 */
}

2. JavaScript 部分(修正计算+优化动画逻辑)

document.querySelectorAll('.image-container').forEach(item => {
    const img = item.querySelector('img');
    let isFirstMove = true; // 标记是否是鼠标进入后的第一次移动

    // 复用的位置计算函数
    const calculateImagePosition = (e) => {
        const rect = item.getBoundingClientRect();
        const mouseY = e.clientY - rect.top; // 鼠标在容器内的相对Y坐标
        const containerHeight = rect.height;
        const imgExcessHeight = img.offsetHeight - containerHeight; // 图片超出容器的高度(可移动范围)
        
        // 计算图片需要移动的距离:鼠标在容器内的比例 * 可移动范围
        const translateYValue = - (mouseY / containerHeight) * imgExcessHeight;
        return translateYValue;
    }

    item.addEventListener('mousemove', (e) => {
        // 用requestAnimationFrame确保动画在浏览器的动画帧执行,避免卡顿
        requestAnimationFrame(() => {
            if (isFirstMove) {
                // 第一次移动用短过渡,避免跳帧
                img.style.transition = 'transform 0.2s ease-out';
                isFirstMove = false;
            } else {
                // 后续移动关闭过渡,保证即时跟随鼠标
                img.style.transition = 'transform 0s';
            }
            const moveY = calculateImagePosition(e);
            img.style.transform = `translateY(${moveY}px)`;
        });
    });

    item.addEventListener('mouseleave', () => {
        // 鼠标离开时用慢过渡复位
        img.style.transition = 'transform 0.8s ease-out';
        img.style.transform = 'translateY(0)';
        isFirstMove = true; // 重置标记,下次进入重新触发
    });

    item.addEventListener('mouseenter', (e) => {
        // 鼠标刚进入时,直接计算当前位置并平滑过渡过去
        isFirstMove = true;
        requestAnimationFrame(() => {
            img.style.transition = 'transform 0.2s ease-out';
            const moveY = calculateImagePosition(e);
            img.style.transform = `translateY(${moveY}px)`;
        });
    });
});

3. HTML 部分(保持不变即可)

<div id="display-grid">
    <div class="cell">
        <div class="image-container">
            <img src="https://framerusercontent.com/images/B7ykrtzOQa5hEXGFIhcq8gyaE.jpg?scale-down-to=1024" alt="作品预览图">
        </div>
        <p>Image Title</p>
    </div>
    <div class="cell">
        <div class="image-container">
            <img src="https://framerusercontent.com/images/B7ykrtzOQa5hEXGFIhcq8gyaE.jpg?scale-down-to=1024" alt="作品预览图">
        </div>
        <p>InfoSwap</p>
    </div>
</div>

关键优化点说明

  1. 修正视差计算:现在的逻辑是根据鼠标在容器内的位置比例,让图片在「可移动范围」内精准跟随,鼠标在容器顶部时图片顶部对齐容器,鼠标在底部时图片底部对齐容器;
  2. 分离过渡逻辑:
    • 鼠标进入/第一次移动:用0.2s短过渡避免跳帧;
    • 鼠标持续移动:关闭过渡,用requestAnimationFrame保证即时跟随,不会滞后;
    • 鼠标离开:用慢过渡平滑复位;
  3. 性能优化:
    • 用requestAnimationFrame包裹动画更新,确保浏览器在合适的时机执行,避免丢帧;
    • 给图片加will-change: transform,让浏览器提前准备优化这个属性的动画,进一步提升流畅度。

备注:内容来源于stack exchange,提问作者Skiddswarmik

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.04.13 18:45:30