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

如何使用CSS与JS实现div左右平滑滑动的页面切换动画

现有代码流畅度差的核心原因

你现在写的效果和目标效果差距大,是几个硬伤导致的:

  • 关键帧定义不一致:fadeOutRight的带webkit前缀版本终点位移是-60px,不带前缀的版本写的是-120px,不同浏览器跑出来的效果不统一
  • 动画时长不合理:2s的转场时长过于拖沓,同类站点的页面滑动转场基本都在300-400ms区间,超过500ms用户就会觉得卡顿、不跟手
  • 未触发硬件加速:直接用2D transform做动画,碰到页面DOM结构复杂的场景,动画会跑在主线程,很容易出现掉帧
  • 缓动函数不匹配:默认的ease曲线运动节奏生硬,没有自然的加速度变化,观感不够顺滑
  • 交互时序错误:点击触发元素后直接添加动画类,没等动画执行完成就触发页面跳转,动画会被浏览器直接打断,必然出现闪屏、卡顿
  • 初始加载动画易闪烁:DOM还没完全就绪就给main节点加动画类,很容易出现内容先正常显示、再突然启动动画的闪烁问题

优化实现方案

完全可以通过CSS+JS实现同等流畅的滑动转场,核心原则是:动画只改transform和opacity两个不触发重排的属性、强制提升到合成层用GPU渲染、控制好动画和页面跳转的时序即可。

优化后的CSS代码

/* 全局禁止横向溢出,避免动画过程中出现滚动条 */
html, body {
  margin: 0;
  overflow-x: hidden;
}
/* 转场基础类:统一配置动画基础参数,强制开启硬件加速 */
.page-transition {
  animation-duration: 380ms;
  animation-fill-mode: both;
  /* 提前告知浏览器该元素会有动画变化,提升到合成层 */
  will-change: transform, opacity;
  backface-visibility: hidden;
}
.header {
  display: flex;
  justify-content: space-evenly;
  position: relative;
  z-index: 10;
}
/* 离场动画:当前页向左滑动60px轻微淡出 */
@keyframes slideOutLeft {
  0% {
    opacity: 1;
    transform: translate3d(0, 0, 0);
  }
  100% {
    opacity: 0.3;
    transform: translate3d(-60px, 0, 0);
  }
}
.slide-out {
  animation-name: slideOutLeft;
  /* 离场用快入缓动,符合点击后的即时反馈感知 */
  animation-timing-function: cubic-bezier(0.4, 0, 1, 1);
}
/* 入场动画:新页面从右侧60px滑入归位 */
@keyframes slideInRight {
  0% {
    opacity: 0.3;
    transform: translate3d(60px, 0, 0);
  }
  100% {
    opacity: 1;
    transform: translate3d(0, 0, 0);
  }
}
.slide-in {
  animation-name: slideInRight;
  /* 入场用慢出缓动,收尾更顺滑 */
  animation-timing-function: cubic-bezier(0, 0, 0.2, 1);
}

优化后的JS代码

document.addEventListener('DOMContentLoaded', () => {
  const main = document.getElementById('main');
  // DOM加载完成后再播放入场动画,避免闪烁
  main.classList.add('page-transition', 'slide-in');

  // 绑定所有转场触发元素
  const triggerEls = document.querySelectorAll('[data-animate]');
  triggerEls.forEach(el => {
    el.addEventListener('click', (e) => {
      // 先阻止默认的即时跳转
      e.preventDefault();
      const targetUrl = el.getAttribute('href');
      
      // 切换为离场动画
      main.classList.remove('slide-in');
      main.classList.add('slide-out');

      // 等离场动画完全执行结束再跳转,保证动画不被打断
      main.addEventListener('animationend', () => {
        window.location.href = targetUrl;
      }, { once: true }); // 单次绑定,避免重复触发
    })
  })
})

对应调整的HTML结构

只需要移除main标签上冗余的初始类即可,其余结构不用改动:

<div class="header">
  <a data-animate href="/pages">main</a>
  <a data-animate href="/pages">main</a>
  <a data-animate href="/pages">main</a>
  <a data-animate href="/pages">main</a>
</div>

<main id="main" class="page-transition">
  <p>Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the industry's standard dummy text ever since the 1500s, when an unknown printer took a galley of type and scrambled it to make a type specimen book. It has survived not only five centuries, but also the leap into electronic typesetting, remaining essentially unchanged. It was popularised in the 1960s with the release of Letraset sheets containing Lorem Ipsum passages, and more recently with desktop publishing software like Aldus PageMaker including versions of Lorem Ipsum.
  </p>
</main>

额外优化提示

如果要做到完全无刷新的丝滑转场,可以去掉真实页面跳转逻辑:点击触发元素时用fetch拉取目标页面的内容,直接替换当前main区域的DOM后播放入场动画,连页面加载的空白间隙都能消除,流畅度会和单页应用完全一致。如果是普通多页站点,上面的方案已经足够达到目标流畅度。

内容的提问来源于stack exchange,提问作者Calvin

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.30 10:09:18