真正稳的波浪动画需叠两层 radial-gradient:一层慢速大波、一层快速小波,background-position 以不同速率移动且周期互质(如8s和12s),配合 background-size 差异、位移值略大于宽度、transform 替代 background-position、overflow: hidden 和 z-index 控制,可避免断点、掉帧与层级问题。

用 ::before 和 ::after 叠两层 radial-gradient 波浪就够了
单靠一个伪元素做“无限流动波浪”会露馅——边缘衔接生硬、速度难调、移动端掉帧。真正稳的方案是叠两层:一层慢速大波,一层快速小波,错开位移周期,视觉上就糊不出断点。
关键不是画多逼真的波形,而是让两层 background-position 以不同速率水平移动,且周期互质(比如 8s 和 12s),自然形成不重复的流动感。
- 别用
linear-gradient拼波浪线——锯齿明显,缩放失真 -
radial-gradient(circle at 50% -50%, transparent 40%, #4a90e2 40%)这类写法能搓出平滑弧顶,再配合background-size: 200% 200%控制波长 - 两层伪元素的
animation-duration必须不同,差值建议 ≥3s,否则容易看出同步抖动
动画卡顿?检查 will-change 和 transform 替代方案
直接 animating background-position 在低端安卓或 Safari 上大概率掉帧,尤其页面有滚动时。更稳妥的做法是把波浪图层抽成独立 div,用 transform: translateX() 驱动,再加 will-change: transform 提前告知浏览器要动它。
- 如果坚持用伪元素,必须给父容器设
overflow: hidden,否则位移过程会溢出显示撕裂 -
transform动画比background-position节省 GPU 资源,但要注意:伪元素无法直接触发硬件加速,得套一层div包裹再动 - Safari 对
radial-gradient+animation组合有渲染 bug,加-webkit-mask-image做遮罩可绕过
@keyframes 里写 100% 位移值不能等于 background-size
常见错误是设 background-size: 400px 200px,然后 @keyframes wave { 0% { background-position: 0 0; } 100% { background-position: 400px 0; } }——这样动画结束瞬间会跳回起点,产生卡顿感。
立即学习“前端免费学习笔记(深入)”;
- 正确做法是让位移值略大于
background-size的宽度,比如background-size: 400px 200px,则100%设为420px,利用浏览器插值平滑过渡 - 两层动画的
background-size宽度最好不同(如 380px / 450px),避免波峰波谷长期重合变“静止” - 别用
%单位写位移,background-position: 100% 0在不同background-size下行为不一致,统一用px
移动端适配:用 vh 控制高度,但禁用 background-attachment: fixed
波浪背景常用于全屏 Banner,用 height: 100vh 最直接。但 iOS Safari 里 background-attachment: fixed 会导致波浪错位甚至消失,必须关掉。
- 改用绝对定位的子容器撑高,父容器设
position: relative,子容器position: absolute; top: 0; left: 0; width: 100%; height: 100vh; - 伪元素的
top/bottom/left/right要设具体值(如top: 0; bottom: 0;),别依赖height: 100%,后者在 flex 容器里可能失效 - Android WebView 对
radial-gradient渲染精度低,加background-repeat: repeat-x并调大background-size宽度能缓解锯齿
最麻烦的其实是波浪和内容文字的层级关系——伪元素默认 z-index 低于内容,但一旦加了 transform 就会创建新层叠上下文,这时候得手动调 z-index,不然文字会被盖住。










