如何用CSS/JS制作一段波浪动画的div?

4
我能想到的一种方法是使用动画svg,但可能有更好的方法。如果你需要动画这些波浪形状(适用于移动设备),你会怎么做? 这里有一个类似的示例链接:http://codepen.io/HeidiChang/pen/gPwPZX
var wave = document.createElement("div");
wave.className += " wave";
docFrag.appendChild(wave);
wave.style.left = i * waveWidth + "px";
wave.style.webkitAnimationDelay = (i / 100) + "s";

触摸交互也会很不错。使用canvas会有任何问题吗? The design

1
兄弟,这么多效果不会让手机死机吗?只是问问。 - Praveen Kumar Purushothaman
1
我尝试了一些动画 SVG,效果还不错。虽然我进行了相当优化...但我还没有尝试过 Canvas。现在可能是时候去试试了。 - Dawid
1
仅供参考,这是我找到的一个很棒的Codepen,它比您提供的那个更好地实现了您想要的功能... https://codepen.io/rstacruz/pen/oxJqNv - Ethan
3个回答

3
这是对@DA.的好答案的实现:

enter image description here

var canvas=document.getElementById('canvas');
var ctx=canvas.getContext('2d');
var cw=canvas.width;
var ch=canvas.height;

ctx.textAlign='center';
ctx.textBaseline='middle';
ctx.font='16px verdana';
ctx.lineWidth=5;
ctx.strokeStyle='white';
ctx.fillStyle='white';
var offsetX=0;

var bk=makeWave(canvas.width,canvas.height-120,10,2,'lightskyblue','cornflowerblue');

requestAnimationFrame(animate);

function animate(time){
    ctx.clearRect(0,0,cw,ch);
    ctx.drawImage(bk,offsetX,0);
    ctx.fillStyle='white';
    ctx.font='18px verdana';
    ctx.fillText('Multiple Lists',cw/2,30);
    ctx.strokeRect(cw/2-50,85,100,50);
    ctx.fillStyle='gray';
    ctx.font='12px verdana';
    ctx.fillText('You can create and save multiple ...',cw/2,250);
    offsetX-=1;
    if(offsetX< -bk.width/2){offsetX=0;}
    requestAnimationFrame(animate);
}

function makeWave(width,midWaveY,amplitude,wavesPerWidth,grad0,grad1){
    var PI2=Math.PI*2;
    var totValue=PI2*wavesPerWidth;
    var c=document.createElement('canvas');
    var ctx=c.getContext('2d');
    c.width=width*2;
    c.height=midWaveY+amplitude;
    var grad=ctx.createLinearGradient(0,0,0,midWaveY);
    grad.addColorStop(0.00,grad0);
    grad.addColorStop(1.00,grad1);
    //
    ctx.beginPath();
    ctx.moveTo(0,0);
    for (x=0;x<=200;x++) {
        var n=totValue*x/100;
        ctx.lineTo(width*x/100,Math.sin(n)*amplitude+midWaveY);
    }
    ctx.lineTo(c.width,0);
    ctx.closePath();
    ctx.fillStyle=grad;
    ctx.fill();
    return(c);
}
body{ background-color:white; }
canvas{border:1px solid red; margin:0 auto; }
<canvas id=canvas width=300 height=300></canvas>


2

我会将这个波浪图形制作成PNG格式(底部为纯灰色,顶部为透明)。将它放在一个宽度是卡片两倍的div中,并将其放在一个与卡片宽度相同的div中(这个第二个div就是“遮罩层”)。

然后通过CSS,在嵌套的div上给它设置x轴变换来使它水平移动。

你不需要使用任何JS来完成这个效果。


1
GIF 没有 alpha 通道,只有透明度。这会显示所有像素。循环播放 PNG 图像需要一定的编码量,可能是 GIF 的 3 倍或 4 倍大小,但边缘会像图片中展示的那样平滑。此外,仅仅侧滑并不是波浪动画。我可以轻松地想象波浪“静止”并在原地振荡。 - pid
1
@pid 噢,好主意。PNG 格式会更好。虽然它不会比 GIF 大 3 倍,但它几乎可以像 GIF 一样压缩。这不需要编码...这不是在循环多个图像。这只是 CSS 动画化一个图像。 - DA.
此外,我猜我不确定OP想要什么样的动画,但通常,是的,波浪上下振荡(就像正弦波)可以通过仅在另一张图像水平滑动来模拟。 - DA.
我同意实际动画。要动画一个简单的波浪(更不用说复杂的了),需要3或4个自由度。OP没有指定任何内容,所以我只是在猜测。最简单的解决方案可能是最好的(就像你说的那样)。 - pid
1
好的解决方案应该能够提供出色的性能。无论使用 SVG 还是 Canvas,您都可以使用简单的正弦波来生成跨越图像大小为 2 个 div 宽度的重复波形模式。此外,图像应从 X 偏移量为0动画到 -image.width/2。当图像达到 -image.width/2 时,则将 X 偏移量设置回0。 - markE

0
我会这样做:
  • 在页面加载时创建一个屏幕外画布(只需设置display: none
  • 在for循环中计算波浪:
    • 使用透明度清除
    • 只绘制白色部分,因为彩色部分有渐变
    • 每次绘制后,从画布中获取PNG数据并将其存储在数组中
  • 循环结束后,您将拥有一组PNG图像(帧)
  • 在不反复重新计算波浪的情况下循环播放这些帧

这需要波浪的周期与您采取的帧数成比例(例如,以10 Hz的2秒动画需要20帧为周期)

老实说,您可以将其存储在服务器端并进行下载,而无需在客户端进行计算。这些PNG图像非常小,因为没有涉及任何颜色(仅透明/白色/alpha通道)。对于此,有最佳设置,我估计每帧约1KB就足够了,即仅有微小的20 KB图像。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接