Parallax

Layers scrolling at different speeds for depth.

Parallax on · layers move at different speeds for depth

html

<div class="mot-plx-stage" data-direction="horizontal">
  <div class="mot-plx-layer mot-plx-back mot-plx-back--on"></div>
  <div class="mot-plx-layer mot-plx-mid mot-plx-mid--on"></div>
  <div class="mot-plx-layer mot-plx-front mot-plx-front--on" style="background:#241430;"></div>
  <p class="mot-plx-caption">Parallax on &middot; layers move at different speeds for depth</p>
</div>
<style>
.mot-plx-stage { position: relative; width: 100%; max-width: 320px; height: 120px; background: linear-gradient(#D9C8F0, #FAF7F2); border-radius: 12px; overflow: hidden; border: 1px solid #24143022; font: 12px system-ui, sans-serif; color: #241430aa; }
.mot-plx-layer { position: absolute; border-radius: 999px; }
.mot-plx-back { width: 40px; height: 40px; background: #BFD9F244; top: 12px; left: 20px; }
.mot-plx-mid { width: 26px; height: 26px; background: #A8E6C199; top: 46px; left: 90px; }
.mot-plx-front { width: 16px; height: 16px; top: 78px; left: 160px; }
.mot-plx-caption { position: absolute; bottom: 4px; left: 8px; right: 8px; }
@media (prefers-reduced-motion: no-preference) {
  [data-direction="horizontal"] .mot-plx-back--on { animation: mot-plx-h-slow 6s linear infinite; }
  [data-direction="horizontal"] .mot-plx-mid--on { animation: mot-plx-h-mid 6s linear infinite; }
  [data-direction="horizontal"] .mot-plx-front--on { animation: mot-plx-h-fast 6s linear infinite; }
  [data-direction="vertical"] .mot-plx-back--on { animation: mot-plx-v-slow 6s linear infinite; }
  [data-direction="vertical"] .mot-plx-mid--on { animation: mot-plx-v-mid 6s linear infinite; }
  [data-direction="vertical"] .mot-plx-front--on { animation: mot-plx-v-fast 6s linear infinite; }
  @keyframes mot-plx-h-slow { 0%,100% { transform: translateX(0); } 50% { transform: translateX(20px); } }
  @keyframes mot-plx-h-mid { 0%,100% { transform: translateX(0); } 50% { transform: translateX(-40px); } }
  @keyframes mot-plx-h-fast { 0%,100% { transform: translateX(0); } 50% { transform: translateX(-80px); } }
  @keyframes mot-plx-v-slow { 0%,100% { transform: translateY(0); } 50% { transform: translateY(10px); } }
  @keyframes mot-plx-v-mid { 0%,100% { transform: translateY(0); } 50% { transform: translateY(-16px); } }
  @keyframes mot-plx-v-fast { 0%,100% { transform: translateY(0); } 50% { transform: translateY(-28px); } }
}
</style>

tailwind

<div class="relative w-full max-w-[320px] h-[120px] rounded-xl overflow-hidden border border-[#24143022] font-sans text-xs text-[#241430]/70" data-direction="horizontal" style="background:linear-gradient(#D9C8F0,#FAF7F2);">
  <div class="tw-plx-back tw-plx-back-on absolute rounded-full w-10 h-10 top-3 left-5 bg-[#BFD9F244]"></div>
  <div class="tw-plx-mid tw-plx-mid-on absolute rounded-full w-[26px] h-[26px] top-[46px] left-[90px] bg-[#A8E6C199]"></div>
  <div class="tw-plx-front tw-plx-front-on absolute rounded-full w-4 h-4 top-[78px] left-40" style="background:#241430;"></div>
  <p class="absolute bottom-1 left-2 right-2">Parallax on &middot; layers move at different speeds for depth</p>
</div>
<style>
@media (prefers-reduced-motion: no-preference) {
  [data-direction="horizontal"] .tw-plx-back-on { animation: mot-plx-tw-h-slow 6s linear infinite; }
  [data-direction="horizontal"] .tw-plx-mid-on { animation: mot-plx-tw-h-mid 6s linear infinite; }
  [data-direction="horizontal"] .tw-plx-front-on { animation: mot-plx-tw-h-fast 6s linear infinite; }
  [data-direction="vertical"] .tw-plx-back-on { animation: mot-plx-tw-v-slow 6s linear infinite; }
  [data-direction="vertical"] .tw-plx-mid-on { animation: mot-plx-tw-v-mid 6s linear infinite; }
  [data-direction="vertical"] .tw-plx-front-on { animation: mot-plx-tw-v-fast 6s linear infinite; }
  @keyframes mot-plx-tw-h-slow { 0%,100% { transform: translateX(0); } 50% { transform: translateX(20px); } }
  @keyframes mot-plx-tw-h-mid { 0%,100% { transform: translateX(0); } 50% { transform: translateX(-40px); } }
  @keyframes mot-plx-tw-h-fast { 0%,100% { transform: translateX(0); } 50% { transform: translateX(-80px); } }
  @keyframes mot-plx-tw-v-slow { 0%,100% { transform: translateY(0); } 50% { transform: translateY(10px); } }
  @keyframes mot-plx-tw-v-mid { 0%,100% { transform: translateY(0); } 50% { transform: translateY(-16px); } }
  @keyframes mot-plx-tw-v-fast { 0%,100% { transform: translateY(0); } 50% { transform: translateY(-28px); } }
}
</style>

react

export function Parallax({
  enabled = true,
  duration = 6,
  direction = "horizontal",
  accent = "#241430",
}) {
  const suffix = direction === "horizontal" ? "h" : "v";
  const on = enabled ? "on" : "";
  return (
    <div data-direction={direction} style={{ position: "relative", width: "100%", maxWidth: 320, height: 120, background: "linear-gradient(#D9C8F0, #FAF7F2)", borderRadius: 12, overflow: "hidden", border: "1px solid #24143022", fontFamily: "system-ui, sans-serif", fontSize: 12, color: "#241430aa" }}>
      <div className={`back ${on}`} style={{ position: "absolute", borderRadius: 999, width: 40, height: 40, top: 12, left: 20, background: "#BFD9F244" }} />
      <div className={`mid ${on}`} style={{ position: "absolute", borderRadius: 999, width: 26, height: 26, top: 46, left: 90, background: "#A8E6C199" }} />
      <div className={`front ${on}`} style={{ position: "absolute", borderRadius: 999, width: 16, height: 16, top: 78, left: 160, background: accent }} />
      <p style={{ position: "absolute", bottom: 4, left: 8, right: 8 }}>Parallax {enabled ? "on" : "off"} &middot; layers move at different speeds for depth</p>
      <style>{`
        @media (prefers-reduced-motion: no-preference) {
          .back.on { animation: mot-plx-${suffix}-slow ${duration}s linear infinite; }
          .mid.on { animation: mot-plx-${suffix}-mid ${duration}s linear infinite; }
          .front.on { animation: mot-plx-${suffix}-fast ${duration}s linear infinite; }
          @keyframes mot-plx-h-slow { 0%,100% { transform: translateX(0); } 50% { transform: translateX(20px); } }
          @keyframes mot-plx-h-mid { 0%,100% { transform: translateX(0); } 50% { transform: translateX(-40px); } }
          @keyframes mot-plx-h-fast { 0%,100% { transform: translateX(0); } 50% { transform: translateX(-80px); } }
          @keyframes mot-plx-v-slow { 0%,100% { transform: translateY(0); } 50% { transform: translateY(10px); } }
          @keyframes mot-plx-v-mid { 0%,100% { transform: translateY(0); } 50% { transform: translateY(-16px); } }
          @keyframes mot-plx-v-fast { 0%,100% { transform: translateY(0); } 50% { transform: translateY(-28px); } }
        }
      `}</style>
    </div>
  );
}