使用两段代码,通过 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/

相关推荐
skywalk81631 分钟前
使用Trae 自动编程:为小学生学汉语项目增加不同出版社教材的区分
服务器·前端·人工智能·trae
huohuopro10 分钟前
LangChain | LangGraph V1教程 #3 从路由器到ReAct架构
前端·react.js·langchain
柒.梧.25 分钟前
HTML入门指南:30分钟掌握网页基础
前端·javascript·html
用户542778485154028 分钟前
Promise :从基础原理到高级实践
前端
用户40993225021231 分钟前
Vue3条件渲染中v-if系列指令如何合理使用与规避错误?
前端·ai编程·trae
Mr_Swilder34 分钟前
2025-12-20 vue3中 eslint9+和prettier配置
前端
code_YuJun36 分钟前
脚手架开发工具——判断文件是否存在 path-exists
前端
code_YuJun36 分钟前
脚手架开发工具——root-check
前端
用户542778485154036 分钟前
XMLHttpRequest、AJAX、Fetch 与 Axios
前端
打小就很皮...44 分钟前
React 实现富文本(使用篇&Next.js)
前端·react.js·富文本·next.js