Animation on Scroll이 있는 헤더바 만들기

12403 단어 ReactemotionReact


나는 상단에 고정되어 있는 헤더를 좋아한다. 그렇지만 헤더 때문에 body가 출력되는 공간이 줄어드는 것은 그닥 좋아하지 않는다. (열린 교회 닫힘) 그래서 이 2가지 취향을 반영하기 위해 아래로 스크롤 시 투명해지는 헤더를 만들었다.


사전에 알아야 될 지식들

우선, CSS-in-JS와 React Hook 개념을 어느정도 숙지해야 해당 포스팅을 따라가기 쉽다. 나는 CSS-in-JS를 위해 emotion을 사용했다.

emotion 공식문서
React Hook 공식문서

스크롤 현재 위치를 어떻게 알까

if (window.pageYOffset > 0) {
    // 스크롤이 아래로 내려갔을 때 
} else {
    // 스크롤이 가장 최상단에 있을 때
}

아무 페이지에서 개발자 모드를 켜서 console.log(window.pageYOffset)을 실행해보면 숫자가 출력되는 것을 확인할 수 있다. window.pageYOffset은 현재 스크롤의 위치를 나타내는 것으로, 0이면 스크롤이 최상단인 것이고 스크롤이 내려갈 수록 그 수가 점점 커진다.

스크롤 움직임을 어떻게 알까

window.addEventListener('scroll', (event) => {
    console.log('Scrolling...');
});

click이나 mouseover 등의 이벤트를 감지할 때 target.addEventListener를 사용한다. scroll도 마찬가지이다. 위 코드를 테스트하면 스크롤바가 움직일 때마다 Scrolling...이 출력되는 것을 확인할 수 있다.


Hook을 이용한 scroll 관리

스크롤이 움직이는 것을 아는 방법과 스크롤의 현재위치를 알아내는 데까지 해냈다. 그럼 이제 이것을 잘 활용해서 scroll이 아래로 내려갔는지, 아닌지 알아내는 state를 하나 만들자.

const [isScroll, setIsScroll] = useState(false);

isScroll이 false면 scroll이 최상단에 있는 것이고, isScroll이 true면 scroll이 조금이라도 아래에 내려온 것이다.

useEffect 이용하기

useEffect(() => {
    window.addEventListener('scroll', () => {
        window.pageYOffset > 0 ? 
        setIsScroll(true) : setIsScroll(false)
    });
}, [isScroll]);

이 경우는 isScroll을 기억하고 있다가 update 하는 경우이다. 따라서 useEffect(func, [isScroll]) 꼴로 만들어주면 된다.


emotion으로 CSS 작성하기

isScroll의 값에 따라 CSS 값을 조정해주면 스크롤 시 애니메이션을 추가해줄 수 있다. 따라서 props에 따라 값을 조정할 수 있는 emotion을 사용해준다. (당연히 styled-component도 가능)

isScroll에 따른 불투명도 설정

const Nav = styled.nav`
  position: fixed; z-index: 1;
  top: 0; right: 0; left: 0;
  opacity: ${props => (props.isScroll ? "0.7" : "1")};
  backdrop-filter: blur(30px);
  padding: 0 20px;
  background: #1c2022;
  display: flex; align-items: center;
  height: 40px;
  transition: all 0.2s ease-in-out;
`;

opacity CSS 속성은 요소의 불투명도를 설정합니다. 불투명도는 요소 뒤쪽 콘텐츠가 숨겨지는 정도로, 투명도의 반대입니다.

opacity는 불투명도를 설정하는 CSS 속성이다. 위와 같이 하면 isScroll이 true일 때는 0.7이 되어 투명해지고, isScroll이 false일 때는 1이 되어 불투명해진다.

코드를 모두 합치면!

import React, { useEffect, useState } from "react";
import styled from "@emotion/styled";

const Nav = styled.nav`
  position: fixed;
  top: 0; right: 0; left: 0;
  z-index: 1;
  opacity: ${props => (props.isScroll ? "0.7" : "1")};
  backdrop-filter: blur(30px);
  padding: 0 20px;
  background: #1c2022;
  display: flex;
  align-items: center;
  height: 40px;
  transition: all 0.2s ease-in-out;
`;

const Navbar = () => {
    const [isScroll, setIsScroll] = useState(false);
  
    useEffect(() => {
      window.addEventListener('scroll', () => {
        window.pageYOffset > 0 ? 
        setIsScroll(true) : setIsScroll(false)
      });
    }, [isScroll]);

    return (
        <div>
            <Nav isScroll={isScroll} />
        </div>
    );
};

export default Navbar;

해당 포스팅에서 언급한 스크롤 애니메이션에 필요한 최소한의 코드는 위와 같다. 여기에 이제 살을 붙이면 헤더바 뚝딱이다. 히히.


레퍼런스

좋은 웹페이지 즐겨찾기