I am trying to copy an open curtain animation like in the
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.
My right white
div
keeps going to the left while I scroll upI 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
div
s
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.