Docs
Two Way Paralalx

Two Way Paralalx

Two way parallax effect.

Additional dependencies:

Lenis (optional)

Scroll Down
img
img
img
img
img
img

Installation

Copy and paste the following code into your project.

components/edil-ozi/two-way-parallax.tsx
"use client";
import { useEffect, useState, useRef, FC } from "react";
import Image from "next/image";
 
import { useScroll, useTransform, motion } from "framer-motion";
 
//optionally hook for smooth scrolling
import useLenis from "@/hooks/useLenis";
 
interface Props {
  images: string[];
}
 
const TwoWayParallax: FC<Props> = ({ images }) => {
  const gallery = useRef(null);
 
  const [dimension, setDimension] = useState({ width: 0, height: 0 });
 
  const { scrollYProgress } = useScroll({
    target: gallery,
    //when to start and end the animation (related to target element)
    offset: ["start end", "end start"],
  });
 
  const { height } = dimension;
  const y1 = useTransform(scrollYProgress, [0, 1], [0, height * 2]);
  const y2 = useTransform(scrollYProgress, [0, 1], [0, height * 3.3]);
  const y3 = useTransform(scrollYProgress, [0, 1], [0, height * 1.25]);
  const y4 = useTransform(scrollYProgress, [0, 1], [0, height * 3]);
 
  // Optionally for smooth scrolling
  useLenis();
 
  useEffect(() => {
    const resize = () => {
      setDimension({ width: window.innerWidth, height: window.innerHeight });
    };
    window.addEventListener("resize", resize);
    resize();
  }, []);
 
  return (
    <div
      ref={gallery}
      className="box-content flex h-[180vh] gap-4 overflow-hidden bg-slate-500 p-4 py-10"
    >
      <Column
        images={[images[0], images[2], images[4]]}
        y={y1}
        classes="top-[-45%]"
      />
      <Column
        images={[images[5], images[6], images[3]]}
        y={y2}
        classes="top-[-95%]"
      />
      <Column
        images={[images[5], images[3], images[2]]}
        y={y3}
        classes="top-[-65%] hidden lg:flex"
      />
      <Column
        images={[images[2], images[0], images[3]]}
        y={y4}
        classes="hidden xl:flex top-[-75%]"
      />
    </div>
  );
};
export default TwoWayParallax;
 
type Column = { images: string[]; y: any; classes: string };
 
const Column = ({ images, y = 0, classes }: Column) => {
  return (
    <motion.div
      style={{ y }}
      className={`relative flex h-full w-full min-w-[180px] flex-col gap-4 ${classes}`}
    >
      {images.map((src, idx) => (
        <div
          key={idx}
          className="relative h-full w-full overflow-hidden rounded-md"
        >
          <Image
            src={src}
            objectFit="cover"
            fill
            alt="img"
          />
        </div>
      ))}
    </motion.div>
  );
};

Notes

This component uses Lenis for smooth scrolling effect. Read more about it here

Credits

This component inspired from Olivier Larose