Ever wanted to add some wavy animations to your app? Look no further! Here's a simple way to create animated waves that can be implemented in any JavaScript app. Let's dive in! πββοΈ
First, we need to define the frames for our wave animation. These are just SVG path data strings.
const frames = [
"M-100,192 C46.67,100,193.33,100,340,192 C486.67,290,633.33,290,780,192 C926.67,100,1073.33,100,1220,192 L1220 600 L-100 600",
"M-100,100 C46.67,100,193.33,292,340,292 C486.67,292,633.33,100,780,100 C926.67,100,1073.33,292,1220,292 L1220 600 L-100 600",
"M-100,192 C46.67,250,193.33,250,340,192 C486.67,150,633.33,150,780,192 C926.67,250,1073.33,250,1220,192 L1220 600 L-100 600",
"M-100,292 C46.67,292,193.33,100,340,100 C486.67,100,633.33,292,780,292 C926.67,292,1073.33,100,1220,100 L1220 600 L-100 600",
"M-100,192 C46.67,100,193.33,100,340,192 C486.67,290,633.33,290,780,192 C926.67,100,1073.33,100,1220,192 L1220 600 L-100 600",
];
This function creates an SVG path element with animated wave motion.
function createWave(dur, beginFrame, direction) {
const path = document.createElementNS("http://www.w3.org/2000/svg", "path");
path.setAttribute("opacity", "0.2");
const animate = document.createElementNS("http://www.w3.org/2000/svg", "animate");
animate.setAttribute("attributeName", "d");
animate.setAttribute("dur", ${dur}s);
animate.setAttribute("begin", ${-(dur / beginFrame)}s);
animate.setAttribute("values", direction === "reverse" ? frames.reverse().join(";") : frames.join(";"));
animate.setAttribute("repeatCount", "indefinite");
animate.setAttribute("keyTimes", "0; 0.25; 0.5; 0.75; 1");
animate.setAttribute("keySplines", "0.42 0 0.58 1; 0.42 0 0.58 1; 0.42 0 0.58 1; 0.42 0 0.58 1");
animate.setAttribute("calcMode", "spline");
path.appendChild(animate);
return path;
}
We should respect users' preferences for reduced motion. Here's how to pause animations if the user prefers reduced motion.
function prefersReducedMotion() {
return window.matchMedia("(prefers-reduced-motion: reduce)").matches;
}
function toggleAnimations(svgElement) {
if (prefersReducedMotion()) {
svgElement.pauseAnimations();
} else {
svgElement.unpauseAnimations();
}
}
Let's put it all together and create the SVG element with our animated waves.
function createWaves(className, duration) {
const svg = document.createElementNS("http://www.w3.org/2000/svg", "svg");
svg.setAttribute("viewBox", "0 0 1320 500");
svg.setAttribute("preserveAspectRatio", "none");
svg.setAttribute("class", "waves");
svg.setAttribute("aria-hidden", "true");
svg.appendChild(createWave(duration, 1, "normal"));
svg.appendChild(createWave(duration, 3, "reverse"));
document.body.appendChild(svg);
toggleAnimations(svg);
// Re-check on preference change
window.matchMedia("(prefers-reduced-motion: reduce)").addEventListener("change", () => toggleAnimations(svg));
}
// Usage
createWaves("my-waves", 5); // className, duration in seconds
Here's some CSS to style the waves.
.waves {
position: fixed;
bottom: 0;
transform: scale(1.3);
width: 100vw;
height: min(325px, 30vh);
}