如何合理实现Font Awesome锁形图标切换时的流畅动画效果
锁形图标翻转动画切换实现方案
实现核心原理
Font Awesome自带的flip动画本质是Y轴旋转,当旋转到90°时图标刚好处于侧面仅显示细线的状态,此时切换两个图标的显隐状态,就能实现翻转到中间换图的效果。
方案1:纯CSS实现(适合hover触发场景)
代码示例
<script src="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.0.0-beta2/js/all.min.js"></script> <link href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.0.0-beta2/css/all.min.css" rel="stylesheet"/> <style> .icon-wrap { position: relative; font-size: 5rem; perspective: 1000px; /* 开启3D透视效果 */ cursor: pointer; } .icon-wrap i { position: absolute; left: 0; top: 0; transition: visibility 0s; } .lock { color: red; } .unlock { color: green; visibility: hidden; /* 初始隐藏解锁图标 */ } /* hover触发翻转动画 */ .icon-wrap:hover .lock { animation: flipSwitch 2s forwards; } .icon-wrap:hover .unlock { animation: flipSwitch 2s forwards reverse; } @keyframes flipSwitch { 0% { transform: rotateY(0deg); visibility: visible; } 49.9% { visibility: visible; } 50% { transform: rotateY(90deg); visibility: hidden; } 100% { transform: rotateY(180deg); visibility: hidden; } } </style> <div class="icon-wrap"> <i class="fas fa-lock lock"></i> <i class="fas fa-unlock unlock"></i> </div>
说明
- 动画总时长可自行调整,
forwards属性保证动画结束后保持最终状态 - 50%节点刚好对应旋转90°的侧面状态,此时切换显隐不会有跳变感
方案2:JS控制(适合点击、自定义事件触发场景)
代码示例
<script src="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.0.0-beta2/js/all.min.js"></script> <link href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.0.0-beta2/css/all.min.css" rel="stylesheet"/> <style> .icon-wrap { position: relative; font-size: 5rem; perspective: 1000px; cursor: pointer; } .icon-wrap i { position: absolute; left: 0; top: 0; } .lock { color: red; } .unlock { color: green; display: none; } .flipping { animation: flipHalf 1s linear; } @keyframes flipHalf { from { transform: rotateY(0deg); } to { transform: rotateY(90deg); } } </style> <div class="icon-wrap" id="lockBtn"> <i class="fas fa-lock lock"></i> <i class="fas fa-unlock unlock"></i> </div> <script> const lockBtn = document.getElementById('lockBtn'); const lockIcon = lockBtn.querySelector('.lock'); const unlockIcon = lockBtn.querySelector('.unlock'); const animDuration = 1000; // 半程动画时长,全程总时长为2倍该值 let isLocked = true; lockBtn.addEventListener('click', () => { // 先执行前半段翻转到90度 lockIcon.classList.add('flipping'); unlockIcon.classList.add('flipping'); setTimeout(() => { // 半程时切换显隐 isLocked = !isLocked; lockIcon.style.display = isLocked ? 'block' : 'none'; unlockIcon.style.display = isLocked ? 'none' : 'block'; // 执行后半段从90度翻转到180度 lockIcon.classList.remove('flipping'); unlockIcon.classList.remove('flipping'); lockIcon.style.transform = isLocked ? 'rotateY(0deg)' : 'rotateY(180deg)'; unlockIcon.style.transform = isLocked ? 'rotateY(180deg)' : 'rotateY(0deg)'; }, animDuration) }) </script>
说明
- 可根据业务需求修改触发事件,比如表单验证通过自动触发切换
- 半程动画时长可自行调整,定时器时长和CSS动画时长保持一致即可
替代优化方案
如果不想同时放两个图标,也可以直接修改单个图标的类名配合transform实现,代码更简洁:
// 点击时半程切换类名 setTimeout(() => { icon.classList.toggle('fa-lock'); icon.classList.toggle('fa-unlock'); icon.style.color = icon.classList.contains('fa-lock') ? 'red' : 'green'; }, animDuration)
内容的提问来源于stack exchange,提问作者Three Year Old
相关产品推荐
相关产品推荐

