리액트와 SCSS로 구현한 눈송이 애니메이션 코드: 사이트에 겨울 불어넣기.

작성 : 2024-01-18수정 : 2024-01-18

목차 펼치기

머리말

어느 날, 카카오톡 채팅방에 눈이 내리기 시작했습니다. 바깥에 눈이 온다고 채팅방에도 눈을 내려주는 것이었죠. 사무실에서 일을 하며 밖을 내다보지 않아도 잠깐 본 카카오톡 채팅방이 밖에는 눈이 내리고 있다는 것을 일러주었습니다. 처음 이 애니메이션을 보았을 때 ‘참 귀엽다’고 생각하며 언젠가는 저도 서비스에 녹여내고 싶었습니다. 이 글은 이번 겨울을 준비하며 React, TypeScript, SCSS를 사용해 눈송이 내리는 애니메이션(이하 눈송이 효과)를 개발한 작업기입니다.


 실제 블로그에 적용해서 동작하는 모습. 눈송이 효과를 On, Off하는 동작까지 보여주고 있다.

실제 블로그에 적용해서 동작하는 모습. 눈송이 효과를 On, Off하는 동작까지 보여주고 있다.


눈 내리는 효과 만들기

챕터 1에서 완성된 예시 코드 및 동작은

Code Sandbox

에서 확인하실 수 있습니다.



눈송이 렌더링 컴포넌트


사이트에 내리는 눈송이들을 정의하는 컴포넌트입니다. 전달받은 숫자만큼 자식 컴포넌트를 렌더링 하는 코드로 크게 어려운 동작은 없습니다.

  • 클라이언트 사이드에서만 실행되도록

    useEffect

    를 활용했습니다.

  • count

    매개변수로 눈송이 개수를 설정할 수 있도록 합니다.

  • 배열을 순회하며 눈송이 아이콘을 렌더링합니다.

    • 만약 눈송이 별로 리렌더링 되는 상황이 생긴다면, 눈송이를 별도의 컴포넌트로 분리해야합니다.

    • 응용하여 눈송이가 아닌 낙엽, 텍스트 등으로 대치 할 수 있습니다.

    • 눈송이 아이콘은

      Iconify의 ion:snow

      코드를 사용했습니다.

  • aria-hidden=”true”

    를 설정하여 스크린리더에 감지되지 않도록 합니다.


랜덤한 눈송이 만들기


눈송이마다 랜덤한 스타일을 지정해줄 수 있도록 코드를 추가했습니다. 랜덤한 숫자가 많이 필요하므로 사용하기 편하게 별도의

generateRandomNumber

함수를 생성해서 사용했습니다.

  • 다음과 같은 스타일을 랜덤으로 지정하여 인라인 스타일로 설정합니다.

    • left

      : 처음 내리기 시작하는 위치.

    • fallDelay

      : 내리기 시작하는 지연시간.

    • shakeDelay

      : 좌우로 흔들리기 시작하는 지연시간.

      fallDelay

      보다 길 경우 눈송이가 일자로 떨어지는 구간이 생기니 주의.

    • blur

      : 눈송이에 흐릿한 효과

    • opacity

      : 눈송이에 투명도 효과

    • size

      : 눈송이 크기

  • IconSnow.tsx

    size

    프로퍼티를 추가해 다른 크기를 전달받을 수 있도록 했습니다.


눈송이 스타일


애니메이션을 비롯해 사용자 선택에서 제외되도록 하는 등 눈송이에 공통적으로 설정할 스타일을 설정합니다.

  • 공통으로 사용할 fall, shake 동작에 대한 애니메이션을 정의합니다.

    • snowflakes-fall

      :

      transform

      을 이용해 눈송이가 수직으로 떨어지는 애니메이션.

    • snowflakes-shake

      :

      transform

      을 이용해 눈송이가 좌우로 흔들리는 애니메이션.

  • 애니메이션 동작에 대한 세부 내용을 정의합니다.

  • pointer-events: none;

    을 설정해 다른 요소 클릭에 방해가 되지 않도록합니다.

  • user-select: none;

    을 설정해 텍스트 선택이 되지 않도록합니다.



On/Off 제어하기

개인 블로그에 적용할 때에는 눈 내리는 애니메이션이 사용자한테 방해가 될 수도 있으므로 제어할 수 있는 권한을 넘겨주도록 했습니다. 홈 화면에서만 사용하기 때문에 로컬스토리지까지 사용하는 것은 좀 과한 것 같아 내부 상태 관리 라이브러리를 통해서만 관리하도록 했으며 홈 화면의 FAB를 통해 제어할 수 있도록 했습니다.


typescript
1interface SnowflakeState {
2  isShow: boolean;
3  change: () => void;
4}
5export const useSnowflakeStore = create<SnowflakeState>(set => ({
6  isShow: true,
7  change: () => set(({ isShow }) => ({ isShow: !isShow })),
8}));

상태 관리 라이브러리 Zustand를 사용해 눈송이 효과를 On/Off 할 수 있는 상태를 추가했으며, Boolean 상태에 따라

className

을 변경해주는 간단한 로직입니다.


개인적으로는 처음으로 Zustand를 사용해서 생성한 State였습니다.



꼬리말

눈송이를 과도하게 만들 경우에는 웹 사이트의 성능이 떨어지고, 랜덤 범위 내 눈송이의 밀도가 높아져 서로 다르게 내리는 것처럼 보이는 효과도 줄어들 수 있으니 사용자 경험을 해치지 않는 선에서 잔잔한 정도의 눈송이가 내리도록 하는 것이 좋습니다.


구글같은 경우에는 내리는 눈송이가 바닥에 쌓이고, 커서가 눈을 치울 수 있도록 하는 기능도 있었던 것이 기억에 납니다. 내리는 것보다 더 특별함을 찾는다면, 한 번 도전해봐도 재미있을 것 같습니다.


그 외에도 내부 아이콘을 변경해서 다양한 아이콘이 흩날리게 할 수도 있기 때문에 봄철에는 벚꽃 아이콘을 흩날리게 하는 것도 재미있을 것 같다고 생각했습니다. 어릴 적 재미있게 본 만화 <블리치>가 생각납니다.


 출처 : 만화 블리치

출처 : 만화 블리치


때로는 기능과 의미, 깊이에의 강요에서 벗어나 단순하게 재미를 따라가 보는 것도 좋은 것 같습니다.

Wanna get in touch?

All Icons byiconiFy