如何防止@media查询导致CSS动画每次越过断点时重复触发
解决方案
你遇到的动画重复触发问题,本质是每次窗口尺寸越过935px断点时,@media规则生效/失效会导致伪元素被销毁/重建,CSS动画会在伪元素每次创建时重新执行。
方案:通过JS首次加载判定动画开关(适配Next.js+Styled Components)
核心逻辑是仅在页面首次加载时判断一次屏幕尺寸,后续窗口大小变化不再修改动画的启用状态,避免伪元素动态重建导致的动画重复触发。
1. 组件内添加状态控制
import { useState, useEffect } from 'react'; import styled from 'styled-components'; export default function Hero() { const [enableTypewriter, setEnableTypewriter] = useState(false); useEffect(() => { // 仅在组件首次挂载时判断一次屏幕尺寸,后续不更新 const shouldAnimate = window.innerWidth >= 935; setEnableTypewriter(shouldAnimate); }, []); // 空依赖数组保证逻辑仅执行一次 return <TypeWriter $enableAnimation={enableTypewriter}>你的打字机动画文案</TypeWriter> }
2. 修改Styled Components代码
把原来写在@media里的伪元素和动画逻辑,改成根据传入的$enableAnimationprop控制:
const TypeWriter = styled.h1` position: relative; font-weight: 800; font-size: 5.4rem; margin-top: 20rem; max-width: 100%; @keyframes typewriter { to { left: 100%; } } @keyframes blink { to { background: transparent; } } /* 仅当prop为true时加载伪元素和动画 */ ${({ $enableAnimation }) => $enableAnimation && ` &::before, &::after { content: ''; position: absolute; top: 0; right: 0; bottom: 0; left: 0; } &::before { background: #e9ecef; animation: typewriter 3s 1s steps(39) forwards; } &::after { background-color: #f9c9d7; animation: typewriter 3s 1s steps(39) forwards, blink 0.7s steps(39) infinite; width: 0.1em; } `} /* 原有其他响应式样式可以保留,不受影响 */ @media screen and (max-width: 934px) { font-size: 3rem; margin-top: 10rem; } `;
方案说明
- 空依赖的useEffect保证判断逻辑只会在页面首次加载时执行一次,后续无论窗口怎么缩放都不会修改动画开关状态
- 使用styled-components的transient prop($开头)避免自定义属性被传递到原生h1 DOM节点上,防止控制台无效属性警告
- 如果需要保留其他响应式样式调整,原有@media规则可以继续正常使用,仅需把伪元素、动画相关逻辑抽离到prop控制分支即可
内容的提问来源于stack exchange,提问作者Achi
相关产品推荐
相关产品推荐

