Parallax Carousel

Parallax Carousel

A fully custom 3D parallax carousel built in vanilla JavaScript. Slides support drag-and-throw interaction, keyboard navigation, auto-play timeline, and responsive breakpoints, with layered parallax motion on both the card content and background.

  • Custom carousel class with drag, inertia & auto-cycle
  • Perspective-based parallax layers on card content & background
  • Accessible pagination dots with ARIA labels
HTML

<!-- Parallax carousel root -->
<div class="mzaCarousel"
     id="mzaCarousel"
     aria-roledescription="carousel"
     aria-label="Featured cards">

  <div class="mzaCarousel-viewport" tabindex="0">
    <div class="mzaCarousel-track">

      <!-- Slide 1 -->
      <article class="mzaCarousel-slide">
        <div class="mzaCard"
             style="--mzaCard-bg:url('https://picsum.photos/id/1015/1600/1000');">
          <header class="mzaCard-head mzaPar-1">
            <h2 class="mzaCard-title">Edge Visuals</h2>
          </header>
          ...
        </div>
      </article>

      <!-- more slides... -->

    </div>
  </div>

  <!-- Prev / Next buttons + dots -->
  <div class="mzaCarousel-controls">...</div>
</div>
CSS

:root {
  --mzaC-fg: #e7ecf2;
  --mzaC-accent: #9ef7d2;
  --mzaC-accent2: #82a0ff;
  ...
}

.mzaCarousel {
  position: relative;
  height: 100vh;
  perspective: 1200px;
  ...
}

.mzaCard {
  backdrop-filter: saturate(120%) blur(4px);
  box-shadow: 0 20px 50px rgba(0,0,0,.45);
  ...
}
JavaScript

// Parallax carousel controller
class MzaCarousel {
  constructor(root, opts = {}) {
    this.root = root;
    this.viewport = root.querySelector(".mzaCarousel-viewport");
    this.slides = [...root.querySelectorAll(".mzaCarousel-slide")];
    ...
  }

  _onDragStart(e) { ... }
  _onDragMove(e) { ... }
  _onDragEnd(e)  { ... }

  _startCycle() { ... }
  _loop() { ... }

  _render(markActive = false) {
    const span = this.slideW + this.state.gap;
    ...
  }
}

window.addEventListener("DOMContentLoaded", () => {
  const root = document.getElementById("mzaCarousel");
  if (!root) return;
  new MzaCarousel(root, { transitionMs: 900 });
});