useEffect
를 사용하여 스크롤 시, 함수가 실행되게 이벤트를 추가해주었다.
그 후 스크롤 시, handleScroll이라는 함수가 동작 할 것이고, scrollY
의 값을 useState
를 선언하여 담아주었다.
const [scrollY, setScrollY] = useState(0);
useEffect(() => {
const handleScroll = () => {
setScrollY(window.scrollY);
};
// 이벤트 등록
window.addEventListener("scroll", handleScroll);
// 메모리 최적화를 위해 이벤트 삭제 (선택사항)
return () => {
window.removeEventListener("scroll", handleScroll);
};
}, []);
그 후 scrollY
값을 CSS에 전달하여 동적 스타일을 적용하기 위해서는 다음과 같이 props
를 전달해주었다.
<StyledHome>
<Sec01>
<BgWrapper scrollY={scrollY}>
<img className="moon" src={"images/landing/bg3.png"} />
<h1>안녕하세요.</h1>
<img className="bg2" src={"images/landing/bg2.png"} />
<img className="bg1" src={"images/landing/bg1.png"} />
<img className="star" src={"images/landing/bg4.png"} />
</BgWrapper>
<DivideBox></DivideBox>
</Sec01>
<Sec02></Sec02>
</StyledHome>
전체 스타일 코드는 아래와 같고, props
한 scrollY
의 값을 어떻게 처리하였는지 보면 된다.
scrollY
*number
<= (요거 각각 다르게 주면, 뷰단에서 이미지들이 이동하는게 불규칙하게 보이게 할 수 있다.)
const extend = keyframes`
0% {
transform: scale(0.7);
}
50% {
transform: scale(0.73);
}
100% {
transform: scale(0.7);
}
`;
const twinkle = keyframes`
0% {
opacity: 0;
}
50% {
opacity: 1;
}
100% {
opacity: 0;
}
`;
const StyledHome = styled.div`
background-color: rgb(28, 5, 34);
width: 100%;
height: fit-content;
display: flex;
flex-direction: column;
`;
const Sec01 = styled.section`
width: 100%;
height: fit-content;
`;
const BgWrapper = styled.div<{ scrollY: number }>`
width: 100%;
height: 100vh;
overflow: hidden;
display: flex;
justify-content: center;
position: relative;
background: linear-gradient(to top, rgb(117, 151, 222), transparent);
> h1 {
font-size: 5rem;
color: white;
position: absolute;
top: ${(props) => props.scrollY * 1 + "px"};
left: 1;
margin-right: ${(props) => props.scrollY * 1.5 + "px"};
margin-top: ${(props) => 300 + props.scrollY * 0.3 + "px"};
z-index: 3;
}
// 가운데 작은 산 배경
.bg2 {
position: absolute;
width: 100%;
height: 100%;
top: ${(props) => props.scrollY * 0.5 + "px"};
object-fit: cover;
z-index: 2;
}
// 큰 산 배경
.bg1 {
position: absolute;
width: 100%;
height: 100%;
left: 0;
top: ${(props) => props.scrollY * 1 + "px"};
z-index: 4;
object-fit: cover;
}
// 별
.star {
position: absolute;
width: 100%;
height: 100%;
left: ${(props) => props.scrollY * 0.5 + "px"};
bottom: ${(props) => props.scrollY * 0.5 + "px"};
animation: ${twinkle} 2s ease-in-out infinite;
z-index: 0;
}
// 달
.moon {
position: absolute;
mix-blend-mode: screen;
animation: ${extend} 3s ease-in-out infinite;
top: ${(props) => -200 + props.scrollY * 2 + "px"};
z-index: 1;
}
`;
const DivideBox = styled.div`
position: absolute;
bottom: -130px;
width: 100%;
height: 80px;
background: linear-gradient(to top, rgb(28, 5, 34), transparent);
z-index: 999;
@media (max-width: 1100px) {
bottom: -55px;
}
`;
const Sec02 = styled.section`
display: flex;
justify-content: center;
padding: 30px;
width: 100%;
height: 2000px;
`;
잘 읽었습니다. 좋은 정보 감사드립니다.