CSS变量本身不能直接生成波浪,但可通过--wave-amplitude、--wave-speed等自定义属性控制mask-size、mask-position及多层动画参数,配合@property声明实现可动画的波浪流动效果。

CSS变量本身不能直接“生成”波浪,但它是控制波浪形边框与背景动态变化最灵活、最可维护的手段——关键在于把波长、振幅、速度、颜色、透明度等参数抽离为--wave-amplitude、--wave-speed这类自定义属性,再在mask-image、clip-path或background-image中引用。
用--wave-wavelength和--wave-amplitude驱动mask-image中的SVG路径
SVG波浪路径里的贝塞尔控制点(如d="M0,5 C50,0 150,10 200,5")不能直接绑定CSS变量,但你可以把整个mask-image写成data URL,并用JS或构建工具注入变量值;更实用的做法是:用CSS变量控制mask-size和mask-position,让同一段SVG波形按需缩放与位移。
-
mask-size: calc(var(--wave-wavelength, 200px) * 1) calc(var(--wave-amplitude, 8px) * 2)—— 控制波峰到波谷的垂直跨度和单个波形宽度 -
mask-position: calc(var(--wave-offset, 0) * 1px) 100%配合@keyframes动画--wave-offset,实现横向流动(注意:纯CSS无法动画CSS变量本身,需配合@property或JS) - 必须加
-webkit-mask-image前缀,Safari 15.4+才支持mask-image动画,旧版需降级为background-position滚动PNG
用--wave-fill和--wave-opacity统一控制多层波浪的视觉层次
多层波浪不是靠堆::before/::after硬写死,而是用CSS变量批量控制每层的填充色与透明度,避免重复声明。例如:
/* 定义三层波浪容器 */
.wave-layer-1 { --wave-fill: #2196F3; --wave-opacity: 0.9; --wave-speed: 5s; }
.wave-layer-2 { --wave-fill: #0D47A1; --wave-opacity: 0.6; --wave-speed: 8s; }
.wave-layer-3 { --wave-fill: #011F4B; --wave-opacity: 0.3; --wave-speed: 12s; }
<p>.wave-layer-1::before,
.wave-layer-2::before,
.wave-layer-3::before {
background: linear-gradient(to right, transparent, var(--wave-fill), transparent);
opacity: var(--wave-opacity);
animation: wave-flow var(--wave-speed) linear infinite;
}- 各层
opacity由--wave-opacity统一管理,改一处即全局生效 -
linear-gradient不能直接画出平滑波形,但配合clip-path或mask-image后,--wave-fill就能精准作用于波浪区域 - 别给同一元素同时设
opacity和background-color: rgba()——会导致双重透明叠加,颜色变灰
为什么@property比JS更适合驱动波浪动画参数
想让--wave-offset随时间变化并被mask-position读取,传统做法是JS定时修改style.setProperty(),但会触发重排。CSS @property提供了声明式方案,让浏览器知道这个变量可动画、有类型、有范围:
立即学习“前端免费学习笔记(深入)”;
@property --wave-offset {
syntax: '<length>';
inherits: false;
initial-value: 0px;
}
<p>.wave-anim {
mask-position: calc(var(--wave-offset) * -1) 100%;
animation: flow 6s linear infinite;
}</p><p>@keyframes flow {
to { --wave-offset: 100px; }
}- 必须显式声明
@property,否则--wave-offset在@keyframes里不会被识别为可动画属性 Chrome 100+/Firefox 110+/Safari 16.4+ 支持,IE和旧Android WebView不支持,需回退到JS方案 -
syntax: '<length>'决定单位合法性,若写成'<number>'却传100px,动画会静默失败
真正难的不是写出第一个动起来的波浪,而是让所有参数——从SVG路径的贝塞尔锚点偏移量,到mask-repeat的接缝对齐,再到多层动画的时长比率——都通过变量联动。一旦漏掉mask-size与--wave-wavelength的单位一致性,或者忘了给父容器加overflow: hidden,波浪就会在边缘撕裂或溢出。这些细节不报错,但效果全毁。


















