小白也能懂的 startViewTransition:一行代码实现丝滑页面过渡
作为前端小白,你是不是也想给页面加个炫酷的过渡动画,却被复杂的 CSS 动画、JS 定时器搞得头大?今天就给大家介绍一个浏览器原生的 "懒人神器"------startViewTransition,一行核心代码就能实现专业级的视图过渡效果,零基础也能上手!
一、startViewTransition 是什么?
简单说,startViewTransition是浏览器自带的视图过渡 API,专门用来处理 "页面内容变化时的过渡动画"(比如点击按钮切换内容、路由跳转、数据刷新)。它把复杂的动画逻辑封装好了,我们只需要告诉它 "什么时候触发过渡""要改什么内容",剩下的交给浏览器就行。
核心特点:
- 原生 API,不用装任何依赖;
- 代码极少,新手易上手;
- 过渡效果丝滑,兼容性(Chrome/Edge 111+、Safari 17+)满足大部分场景。
二、最简案例:点击按钮切换内容
先看效果:点击按钮,盒子从红色变成蓝色,宽度从 100px 变 200px,过程有自然的过渡动画。
1. 完整代码(直接复制就能跑)
预览
html
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<title>startViewTransition小白案例</title>
<style>
/* 基础样式:给盒子加过渡的基础配置 */
#box {
width: 100px;
height: 100px;
background: red;
/* 关键:让样式变化能被过渡捕获(可省略,API会自动处理,但加了更稳) */
transition: all 0.5s ease;
}
button {
margin-top: 20px;
padding: 8px 16px;
cursor: pointer;
}
</style>
</head>
<body>
<div id="box"></div>
<button id="btn">点击切换样式</button>
<script>
// 1. 获取元素
const box = document.getElementById('box');
const btn = document.getElementById('btn');
// 2. 点击按钮触发过渡
btn.addEventListener('click', () => {
// 核心代码:调用startViewTransition
document.startViewTransition(() => {
// 这里写你要修改的DOM内容/样式
box.style.width = '200px';
box.style.background = 'blue';
});
});
</script>
</body>
</html>
2. 代码解释
document.startViewTransition():调用过渡 API,括号里传一个函数;- 函数内部:写你要修改的 DOM 操作(比如改样式、改文本、删加元素);
- API 会自动捕获 "修改前的 DOM 状态" 和 "修改后的 DOM 状态",然后生成过渡动画。
运行后点击按钮,你会看到盒子不是 "瞬间变化",而是有 0.5 秒的渐变过渡 ------ 这就是startViewTransition的魔力!
三、进阶一点:路由 / 页面切换场景
实际开发中,我们常需要 "点击导航切换页面内容",用这个 API 也能轻松实现。
案例(模拟路由切换)
预览
html
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<title>页面内容切换过渡</title>
<style>
.page {
width: 300px;
height: 200px;
display: none; /* 默认隐藏所有页面 */
padding: 20px;
box-sizing: border-box;
}
.page.active {
display: block;
}
.nav {
margin-bottom: 10px;
}
.nav button {
margin-right: 10px;
}
</style>
</head>
<body>
<div class="nav">
<button data-page="page1">页面1</button>
<button data-page="page2">页面2</button>
</div>
<div id="page1" class="page active">我是页面1的内容</div>
<div id="page2" class="page">我是页面2的内容</div>
<script>
// 获取所有导航按钮
const navBtns = document.querySelectorAll('.nav button');
// 给每个按钮加点击事件
navBtns.forEach(btn => {
btn.addEventListener('click', () => {
// 要切换的目标页面ID
const targetPage = btn.dataset.page;
// 核心:调用过渡API
document.startViewTransition(() => {
// 隐藏所有页面
document.querySelectorAll('.page').forEach(page => {
page.classList.remove('active');
});
// 显示目标页面
document.getElementById(targetPage).classList.add('active');
});
});
});
</script>
</body>
这个案例中,点击 "页面 1 / 页面 2",内容切换会有原生的淡入淡出过渡,不用自己写关键帧动画!
主题切换
element-plus 官网的主题切换效果
vue
<template>
<vab-icon
class="dark"
:icon="mode === 'dark' ? 'moon' : 'sun'"
@click="toggleDark"
/>
</template>
<script lang="ts" setup>
defineOptions({
name: 'ThemeSwitcher',
})
const toggleDark = async (event: MouseEvent) => {
if (typeof document.startViewTransition === 'function') {
const x = event.clientX
const y = event.clientY
const endRadius = Math.hypot(Math.max(x, innerWidth - x), Math.max(y, innerHeight - y))
let isDark: boolean
const transition = document.startViewTransition(() => {
const root = document.documentElement
isDark = root.classList.contains('dark')
root.classList.remove(isDark ? 'dark' : 'light')
root.classList.add(isDark ? 'light' : 'dark')
})
await transition.ready.then(() => {
const clipPath = [`circle(0px at ${x}px ${y}px)`, `circle(${endRadius}px at ${x}px ${y}px)`]
document.documentElement.animate(
{
clipPath: isDark ? [...clipPath].reverse() : clipPath,
},
{
duration: 600,
fill:'both',
easing: 'ease-in',
pseudoElement: isDark ? '::view-transition-old(root)' : '::view-transition-new(root)',
}
)
})
}
}
</script>
<style lang="scss">
::view-transition-old(root),
::view-transition-new(root) {
mix-blend-mode: normal;
animation: none;
}
::view-transition-old(root) {
z-index: 999;
}
::view-transition-new(root) {
z-index: 1;
}
.dark {
&::view-transition-old(root) {
z-index: 1;
}
&::view-transition-new(root) {
z-index: 999;
}
}
.dark {
position: relative;
margin-left: var(--el-margin);
cursor: pointer;
transition: var(--el-transition);
}
</style>
四、常见小配置:fill: 'both'(小白必知)
有时候过渡动画结束后,样式会 "回退",这时候可以加个配置:
javascript
运行
arduino
document.startViewTransition(() => {
// 你的DOM修改逻辑
box.style.width = '200px';
}, {
fill: 'both' // 关键:让动画前后都保留最终样式
});
fill: 'both'的通俗理解:
- 动画开始前:提前应用最终样式(不会有 "延迟空白");
- 动画结束后:保留最终样式(不会回退到初始状态);
- 简单说就是 "动画前后都生效",避免样式闪回。
五、注意事项
- 兼容性:目前仅现代浏览器支持(Chrome/Edge/Safari 新版),低版本浏览器会 "无过渡但功能正常",不影响使用;
- 只能捕获 DOM 变化:函数内部必须是真实的 DOM 修改(比如改样式、增删元素),异步操作要包在里面;
- 不要嵌套调用:一个过渡没结束前,不要触发下一个,否则会卡顿。
总结
startViewTransition是浏览器原生 API,专门做视图过渡,不用写复杂动画;- 核心用法:
document.startViewTransition(() => { 你的DOM修改逻辑 }); fill: 'both'能解决样式回退问题
这个 API 可以说是前端的 "动画神器",不用懂复杂的 CSS 动画原理,一行核心代码就能实现丝滑过渡,赶紧复制案例试试吧!