使用两段代码,通过 View Transitions API 为主题切换添加平滑过渡动画

😀 在 Web 开发中,主题切换通常是即时生效的,但这种方式会导致用户视觉上的突兀感。通过 View Transitions API,我们可以实现更流畅的切换动画,让深色模式和浅色模式的过渡更加自然。

功能描述

点击 Switch 组件切换主题时,页面会从点击位置向外扩散,形成类似"水波扩散"的动画效果,使切换过程更具视觉吸引力。

Demo 仓库

核心代码

  1. 主题切换逻辑 在主题切换处理函数中:
ts 复制代码
const handleThemeChange: SwitchProps["onChange"] = (checked: boolean, event) => {
  // 必须加这句
  document.documentElement.className = checked ? "dark" : "light";

  // 获取点击位置,或者回退到页面中间
  const x = event instanceof MouseEvent ? event?.clientX / 2 : innerWidth;
  console.log(x);
  const y = event instanceof MouseEvent ? event?.clientY / 2 : innerHeight;
  // 获取到最远角的距离
  const endRadius = Math.hypot(Math.max(x, innerWidth - x), Math.max(y, innerHeight - y));
  const circlePath = [`circle(0 at ${x}px ${y}px)`, `circle(${endRadius}px at ${x}px ${y}px)`];

  // 执行主题切换
  const transition = document.startViewTransition(() => {
    setIsDarkMode(checked);
  });

  // 监听过渡动画的就绪状态
  transition.ready.then(() => {
    document.documentElement.animate(
      {
        clipPath: checked ? circlePath : [...circlePath].reverse(),
      },
      {
        duration: 1000,
        easing: "ease-in",
        pseudoElement: checked ? "::view-transition-new(root)" : "::view-transition-old(root)",
      }
    );
  });
};

document.startViewTransition:执行 dom 更改代码,在 React 中则为发起渲染更新。

transition.ready.then:前后两张快照之间的过渡动画。

  1. 配置全局样式

为了确保 View Transitions 正常工作,需要添加一些 CSS 规则:

css 复制代码
/** Animated Theme Toggle */
::view-transition-old(root),
::view-transition-new(root) {
  animation: none;
  mix-blend-mode: normal;
}

.dark::view-transition-old(root) {
  z-index: 1;
}

.dark::view-transition-new(root) {
  z-index: 999;
}

::view-transition-old(root) {
  z-index: 999;
}

::view-transition-new(root) {
  z-index: 1;
}

总结

  • 核心思路:利用 View Transitions API,通过 clipPath 创建动态扩散动画。
  • 动画细节:根据鼠标点击位置,计算扩散路径,使视觉效果更自然。
  • 兼容性:目前 View Transitions 主要支持 Chrome 111+,其他浏览器支持情况可参考 Can I Use。

这种方式不仅提升了用户体验,还让主题切换更加流畅和现代化。🚀

参考资料

developer.mozilla.org/zh-CN/docs/...

ant.design/index-cn/

相关推荐
且白16 分钟前
vsCode使用本地低版本node启动配置文件
前端·vue.js·vscode·编辑器
程序研17 分钟前
一、ES6-let声明变量【解刨分析最详细】
前端·javascript·es6
siwangqishiq242 分钟前
Vulkan Tutorial 教程翻译(四) 绘制三角形 2.2 呈现
前端
李三岁_foucsli43 分钟前
js中消息队列和事件循环到底是怎么个事,宏任务和微任务还存在吗?
前端·chrome
尽欢i44 分钟前
HTML5 拖放 API
前端·html
PasserbyX1 小时前
一句话解释JS链式调用
前端·javascript
1024小神1 小时前
tauri项目,如何在rust端读取电脑环境变量
前端·javascript
Nano1 小时前
前端适配方案深度解析:从响应式到自适应设计
前端
古夕1 小时前
如何将异步操作封装为Promise
前端·javascript
小小小小宇1 小时前
前端定高和不定高虚拟列表
前端