Skip to content

Instantly share code, notes, and snippets.

@codebycarlos
Last active July 9, 2024 08:36
Show Gist options
  • Save codebycarlos/84f2f12d51eb48f8e6b622e044250785 to your computer and use it in GitHub Desktop.
Save codebycarlos/84f2f12d51eb48f8e6b622e044250785 to your computer and use it in GitHub Desktop.
Waves: everybody loves waves!

🌊 Wavy Animations for Your JavaScript App

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! πŸŠβ€β™‚οΈ

1. Define the Wave Frames

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",
];

2. Create the Wave Component

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;
}

3. Accessibility: Pause Animations for Reduced Motion

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();
  }
}

4. Assemble the Waves!

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

5. Styling the Waves

Here's some CSS to style the waves.

.waves {
  position: fixed;
  bottom: 0;
  transform: scale(1.3);
  width: 100vw;
  height: min(325px, 30vh);
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment