如何在不同设备上实现同元素的差异化CSS动画效果
需求实现说明
这个需求完全可以实现。你原有代码不生效的核心原因是:CSS 不支持在媒体查询中直接重写同名@keyframes规则,浏览器解析CSS时会直接采用最后定义的同名关键帧,完全忽略媒体查询内的同名定义,所以不管在桌面端还是移动端,最终都会加载蓝色的关键帧配置。
另外你原有代码还缺少animation-fill-mode: forwards配置,动画播放结束后会直接回弹到初始样式,没法保持最后一帧的颜色。
推荐实现方案(纯CSS,无额外JS逻辑)
不要给不同端的关键帧设置相同名称,分别定义移动端、桌面端独立命名的关键帧,在对应媒体查询下给.anim类绑定对应动画名即可,修正后的完整代码如下:
<!-- HTML部分保持原有结构即可 --> <div class="box"></div><br> <button id="play">Play</button>
.box { display: flex; width: 4rem; height: 4rem; border: 1px dashed gray; } .anim { animation-duration: .25s; animation-timing-function: ease-in-out; /* 关键配置:动画结束后保持最后一帧样式 */ animation-fill-mode: forwards; } /* 桌面端适配 */ @media only screen and (min-width: 992px) { .anim { animation-name: rainbow-desktop; } @keyframes rainbow-desktop { 0% {background-color: transparent;} 100% {background-color: red;} } } /* 移动端适配 */ @media (max-width: 991px) { .anim { animation-name: rainbow-mobile; } @keyframes rainbow-mobile { 0% {background-color: transparent;} 100% {background-color: blue;} } }
// JS部分保持原有触发逻辑即可 var box = document.getElementsByClassName('box'); document.getElementById("play").addEventListener("click", () => { // 支持重复点击播放:先移除类触发重绘,再重新添加动画类 box[0].classList.remove('anim'); void box[0].offsetWidth; box[0].classList.add('anim'); });
备选方案(JS监听控制)
如果需要更灵活的逻辑扩展,可以监听animationend事件,在动画结束时判断当前视口宽度,直接给元素添加对应颜色的样式类:
const box = document.getElementsByClassName('box')[0]; document.getElementById("play").addEventListener("click", () => { box.classList.remove('anim', 'bg-red', 'bg-blue'); void box.offsetWidth; box.classList.add('anim'); }); box.addEventListener('animationend', () => { const isDesktop = window.matchMedia('(min-width: 992px)').matches; box.classList.add(isDesktop ? 'bg-red' : 'bg-blue'); });
/* 补充颜色类 */ .bg-red {background-color: red;} .bg-blue {background-color: blue;}
注意:
void element.offsetWidth的作用是触发浏览器重绘,保证移除动画类再重新添加时,动画可以重复触发,不会出现第二次点击没反应的问题。
内容的提问来源于stack exchange,提问作者mkiuygfd
相关产品推荐
相关产品推荐

