스크롤을 활용한 자연스러운 웹사이트 구현

woodylovesboota·2024년 1월 2일
0
post-thumbnail

스크롤 값을 이용하여 시각적으로 자연스러운 웹사이트를 만들 수 있다.

현재 위치 가져오기

window 객체를 이용하여 현재 위치를 알 수 있다.

window.addEventListener("scroll", ()=> { console.log(window.scrollY) })

React의 useEffect를 이용하여 이를 state화 시키면 React에서 사용자의 scroll 위치를 이용할 수 있다.

  const [scrollY, setScrollY] = useState(0);

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

이를 이용해 스크롤에 따라 스타일이 변하는 컴포넌트를 만들 수 있다. 나는 스크롤이 최상단에 있을 때 크기가 커지는 Navigation Bar 를 만들었다.

<Wrapper istop={scrollY === 0}>
...
</Wrapper>

const Wrapper = styled.div<{ istop: boolean }>`
	height: ${(props) => (props.istop ? "80px" : "60px")};
`;

스크롤 이동시키기

React의 useRef의 scrollIntoView를 이용하여 특정 컴포넌트로 스크롤을 이동시킬 수 있다.

const boxRef = useRef<HTMLDivElement>(null);
const onClick = () => {
  boxRef.current?.scrollIntoView({ behavior: "smooth" });
};
...
<Box ref={boxRef} />
<Button onClick={onClick}>Box로 이동</Button>

Method

https://developer.mozilla.org/ko/docs/Web/API/Element/scrollIntoView

컴포넌트의 위치(위, 아래, 중앙 등)나 스크롤 속도(smooth, instant)등을 설정할 수 있다.

이를 이용하여 특정 컴포넌트로 이동시켜주는 Navigaton Bar를 만들 수 있다.

const portfolioRef = useRef<HTMLDivElement>(null);
const onPortfolioClick = () => {
  portfolioRef.current?.scrollIntoView({ behavior: "smooth"!
 });
};

<Content onClick={onPortfolioClick}>PORTFOLIO</Content>
...
<Portfolios ref={portfolioRef} />

block : "center"를 이용해 주면 컴포넌트의 중앙으로 이동할 수 도 있다.

const portfolioRef = useRef<HTMLDivElement>(null);
const onPortfolioClick = () => {
  portfolioRef.current?.scrollIntoView({ behavior: "smooth", block: "center" });
};

<Content onClick={onPortfolioClick}>PORTFOLIO</Content>
...
<Portfolios ref={portfolioRef} />

컴포넌트에 도착하면 State 변화시키기

내가 생각한 방법은

  1. useRef를 이용하여 컴포넌트의 scrollY 값 가져오기
  2. 현재 사용자의 scroll 값과 비교하기
  3. 특정 조건에서 state 변화시키기

이었는데 _useRef를 이용하여 컴포넌트의 scrollY 값 가져오기_가 되지 않아 어려움이 있었다.

내가 원했던 기능은 특정 컴포넌트에 다다르면 Navigation Bar에서 이를 확인할 수 있게 하는 것이었기 때문에 컴포넌트의 수가 많지 않았고, 위에서 부터 컴포넌트의 scrollHeight를 다 더해가는 식으로 구현하였다.

useEffect(() => {
  if (scrollY < mainRef.current?.scrollHeight + 300) setIsnow(0);
  else if (
    scrollY > mainRef.current?.scrollHeight + 300 &&
    scrollY < mainRef.current?.scrollHeight + portFolioRef.current.scrollHeight + 300) setIsnow(1);
  else if (
    scrollY > mainRef.current?.scrollHeight + portFolioRef.current.scrollHeight + 300 &&
	scrollY < mainRef.current?.scrollHeight + portFolioRef.current.scrollHeight + blogRef.current.scrollHeight + 300)  setIsnow(2);
 
else if ( scrollY > mainRef.current?.scrollHeight + portFolioRef.current.scrollHeight + blogRef.current.scrollHeight + 300 ) setIsnow(3);
}, [scrollY]);

...

<MainContent ref={mainRef} />
<Projects ref={portfolioRef} />
<Blog ref={blogRef} />
<Contact ref={contactRef} />

컴포넌트는 위에서 부터 다음과 같이 배치되어 있다.

  1. Main
  2. Portfolio
  3. Blog
  4. Contact

Main 높이 < scrollY < Main 높이 + Portfolio 높이 이면 isnow를 변경하여 Portfolio에 있다고 하는 식으로 구현하였다.

마지막으로 Navigation Bar에 isnow를 이용하여 스타일을 변화해 주었다.

<Content onClick={onBlogClick}>BLOG{isnow === 2 && <UnderBar />}</Content>

고정된 위치로 스크롤 이동하기

특정 컴포넌트로 이동시키는게 목적이 아니라면 window의 scrollTo()를 이용하면 된다.

<Button onClick={() => { window.scrollTo(0, 0); }}>BACK TO TOP</Button>

0개의 댓글