如何实现类似Telegram、VK的主题切换按钮动画效果
主题切换按钮动画实现方案
核心实现思路
Telegram、VK的主题切换动画核心是两个图标的状态过渡+按钮背景的形变动效,不需要复杂的第三方库,用CSS过渡/动画加少量JS触发状态即可实现。
方案1:纯CSS图标淡入淡出+旋转过渡(最简单实现)
- 把太阳、月亮两个图标重叠放在按钮容器里,默认显示当前主题对应的图标,另一个设置
opacity: 0、transform: rotate(90deg)隐藏 - 给两个图标都加上
transition: all 0.3s ease过渡属性 - 主题切换时给按钮加一个标识类(比如
is-dark),切换两个图标的opacity和rotate值,就能实现图标旋转交替出现的效果
示例代码:
<button class="theme-toggle"> <svg class="icon sun"><!-- 太阳图标代码 --></svg> <svg class="icon moon"><!-- 月亮图标代码 --></svg> </button>
.theme-toggle { position: relative; width: 40px; height: 40px; border: none; border-radius: 50%; background: #e0e0e0; cursor: pointer; } .theme-toggle .icon { position: absolute; top: 50%; left: 50%; transform: translate(-50%, -50%) rotate(0); transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1); z-index: 1; } /* 暗色模式下的状态 */ .theme-toggle.is-dark { background: #2d2d2d; } .theme-toggle.is-dark .sun { opacity: 0; transform: translate(-50%, -50%) rotate(90deg); } .theme-toggle:not(.is-dark) .moon { opacity: 0; transform: translate(-50%, -50%) rotate(-90deg); }
const toggleBtn = document.querySelector('.theme-toggle') toggleBtn.addEventListener('click', () => { toggleBtn.classList.toggle('is-dark') // 这里加你原有切换主题的逻辑 })
方案2:Telegram同款形变过渡(更还原效果)
如果要做到Telegram那种太阳变月亮/月亮变太阳的形变效果,可以用CSS clip-path或者SVG morphing实现:
- 用单个SVG路径同时定义太阳和月亮的形状,切换时修改
d属性值,配合过渡实现形状渐变 - 也可以给按钮加背景填充动效:点击时从按钮点击位置扩散圆形填充,同步切换主题色
核心代码示例:
/* 扩散填充效果 */ .theme-toggle::before { content: ''; position: absolute; top: 50%; left: 50%; width: 0; height: 0; border-radius: 50%; background: #121212; transform: translate(-50%, -50%); transition: width 0.4s ease, height 0.4s ease; z-index: 0; } .theme-toggle.is-dark::before { width: 150%; height: 150%; }
优化建议
- 过渡曲线用
cubic-bezier(0.4, 0, 0.2, 1)更符合常用动效规范,和Telegram的动效节奏接近 - 动画时长控制在0.3-0.4s之间,太长会显得卡顿,太短没有过渡感
- 可以给按钮加上hover时的缩放效果,增强交互感:
.theme-toggle:hover { transform: scale(1.1); }
内容的提问来源于stack exchange,提问作者Anatoly Kuznetsov
相关产品推荐
相关产品推荐

