Element-Plus官网黑夜模式切换动画效果的实现
前言
在使用Element-Plus时,发现有两个很有趣的效果,一个是header的背景模糊效果,另一个是黑夜模式切换动画,在此我们先来研究一下黑夜模式切换动画效果是如何实现的。
代码
html部分
<div id="box">
<input type="checkbox" id="checkBox">
<label for="checkBox"></label>
</div>
<iframe src="https://www.baidu.com"></iframe>
css部分
html,
body {
background-color: #fff;
height: 100vh;
display: flex;
flex-direction: column;
}
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
iframe {
flex: 1;
}
html.dark {
filter: invert(1) hue-rotate(180deg);
img,
video,
.avatar,
.image,
.thumb,
#box {
filter: invert(1) hue-rotate(180deg);
}
}
::view-transition-old(root),
::view-transition-new(root) {
animation: none;
mix-blend-mode: normal;
}
::view-transition-old(root) {
z-index: 1;
}
::view-transition-new(root) {
z-index: 2147483646;
}
html.dark::view-transition-old(root) {
z-index: 2147483646;
}
html.dark::view-transition-new(root) {
z-index: 1;
}
#checkBox {
opacity: 0;
width: 0;
}
#box>label {
display: block;
width: 70px;
height: 30px;
border-radius: 30px;
border: 1px solid #dcdfe6;
background-color: #f2f2f2;
position: relative;
transition: all 0.3s;
display: flex;
align-items: center;
}
#checkBox:checked+label {
background-color: #2c2c2c;
border: 1px solid #4c4d4f;
}
#box>label::before {
content: '🌞';
position: absolute;
left: 0;
line-height: 25px;
font-size: 18px;
text-align: center;
background-color: #fff;
border-radius: 18px;
border: 1px solid #dcdfe6;
transition: all 0.3s;
}
#checkBox:checked+label::before {
display: none;
}
#checkBox+label::after {
content: '🌙';
position: absolute;
display: none;
left: 0;
line-height: 25px;
font-size: 18px;
text-align: center;
background-color: #141414;
border-radius: 18px;
border: 1px solid #4c4d4f;
transition: all 0.3s;
}
#checkBox:checked+label::after {
left: calc(100% - 26px);
right: 0;
display: block;
border: 1px solid #4c4d4f;
transition: all 0.3s;
}
js部分
document.getElementById('checkBox').addEventListener('click', function (event) {
toggleTheme(event);
});
// 切换主题
function toggleTheme(event) {
// 检查浏览器是否支持 View Transition API
if (!document.startViewTransition) {
// 不支持则直接切换主题,不添加动画
document.documentElement.classList.toggle('dark')
return
}
const transition = document.startViewTransition(() => {
document.documentElement.classList.toggle('dark')
})
transition.ready.then(() => {
const { clientX, clientY } = event
const endRadius = Math.hypot(Math.max(clientX, innerWidth - clientX), Math.max(clientY, innerHeight - clientY))
const clipPath = [`circle(0px at ${clientX}px ${clientY}px)`, `circle(${endRadius}px at ${clientX}px ${clientY}px)`]
const isDark = document.documentElement.classList.contains('dark')
document.documentElement.animate(
{
clipPath: isDark ? clipPath.reverse() : clipPath
},
{
duration: 450,
easing: 'ease-in',
pseudoElement: isDark ? '::view-transition-old(root)' : '::view-transition-new(root)'
}
)
})
}
上面切换动画效果的实现用到了View Transition API,同时,用到了filter: invert(1) hue-rotate(180deg)来实现滤镜反色,以确保不同主题下背景和内容之间的对比度。
大家快去实现一下吧!
人心如良苗,得养乃滋长。苗以泉水灌,心以理义养。一日不读书,胸臆无佳想。一月不读书,耳目失精爽。

浙公网安备 33010602011771号