Home > database >  How to implement open curtain animation
How to implement open curtain animation

Time:10-12

I am trying to copy an open curtain animation like in the enter image description here

I have a working example with the following code

import { useState, useEffect, useRef, useCallback } from "react";
import "./styles.css";

export default function App() {
  // check window scroll direction
  const [y, setY] = useState(null);
  const [scrollDirection, setScrollDirection] = useState("");

  const boxTwo = useRef(null);
  const boxTwoLeft = useRef(null);
  const boxTwoRight = useRef(null);
  const countRefTranslateX = useRef(0);

  // check window scroll direction https://stackoverflow.com/questions/62497110/detect-scroll-direction-in-react-js
  const handleScrollDirection = useCallback(
    (e) => {
      const window = e.currentTarget;
      if (y > window.scrollY) {
        setScrollDirection("up");
      } else if (y < window.scrollY) {
        setScrollDirection("down");
      }
      setY(window.scrollY);
    },
    [y]
  );

  const handleScroll = useCallback(() => {
    if (boxTwo.current) {
      let position = boxTwo.current.getBoundingClientRect();
      // checking for partial visibility and if 50 pixels of the element is visible in viewport
      if (
        position.top   50 < window.innerHeight &&
        position.bottom >= 0 &&
        scrollDirection === "down"
      ) {
        countRefTranslateX.current = countRefTranslateX.current   3;
        boxTwoLeft.current.style.transform = `translateX(-${countRefTranslateX.current}px)`;
        boxTwoRight.current.style.transform = `translateX(${countRefTranslateX.current}px)`;
      } else if (
        position.top   50 < window.innerHeight &&
        position.bottom >= 0 &&
        scrollDirection === "up"
      ) {
        countRefTranslateX.current = countRefTranslateX.current - 3;
        boxTwoLeft.current.style.transform = `translateX(-${countRefTranslateX.current}px)`;
        boxTwoRight.current.style.transform = `translateX(${countRefTranslateX.current}px)`;
      } else {
        countRefTranslateX.current = 0;
        boxTwoLeft.current.style.transform = `translateX(-${countRefTranslateX.current}px)`;
        boxTwoRight.current.style.transform = `translateX(${countRefTranslateX.current}px)`;
      }
    }
  }, [scrollDirection]);

  useEffect(() => {
    window.addEventListener("scroll", handleScroll);
    return () => {
      window.removeEventListener("scroll", handleScroll);
    };
  }, [handleScroll]);

  useEffect(() => {
    setY(window.scrollY);
    window.addEventListener("scroll", handleScrollDirection);
    return () => {
      window.removeEventListener("scroll", handleScrollDirection);
    };
  }, [handleScrollDirection]);

  return (
    <div className="App">
      <div className="boxOne"></div>
      <div ref={boxTwo} className="boxTwo">
        <div ref={boxTwoLeft} className="boxTwoLeft"></div>
        <div ref={boxTwoRight} className="boxTwoRight"></div>
      </div>
      <div className="boxThree"></div>
    </div>
  );
}

I have two issues.

  1. My right white div keeps going to the left while I scroll up

  2. I cannot get a fixed vertical window breakpoint. My animation continues after the window has scrolled after the point I want to start/stop moving the divs

How can I resolve these issues?

My codesandbox

CodePudding user response:

I've looked over what you've done but it's way too complicated.

All you want is to place two curtains (panels) on top of your content. The container should have position:relative and the curtains should have position: absolute.

You then declare the scrollLimits in between which they should move. In the example below, 0 is the starting point and window.innerHeight the end point. Replace those values with whatever makes sense for your section, considering its vertical position in the page. You could use the section's current offsetTop and clientHeight to set the limits dynamically, based on current window size.

You then get the current scroll position and calculate the scroll percentage relative to the limits.

You then apply the percentage/2 50% to each curtain's transform: translateX() the left one with negative value, the right one with positive value.

Done.

Note: change the CSS selectors so the styles apply to your section only.

Edit: I've come up with a more generic way to set the scroll interval, using the section's getBoundingClientRect().top and window.innerHeight. It's probably more useful, as you no longer have to worry about the section's position in page.
I've left the previous version in, for reference and/or for anyone who prefers it.

  • Related