공부/React

[React/리액트] TypeScript+SCSS 눈 내리는 효과 만들기

딜레이레이 2023. 12. 14. 15:44

https://codepen.io/alphardex/pen/dyPorwJ

 

Snow (Pure CSS)

Inspired by: https://codepen.io/YusukeNakaya/pen/NWPqvWW This is a pure CSS version :d...

codepen.io

 

위 css 효과를 React 페이지에서 적용해보려고 한다.
우선 css 파일을 하나씩 살펴보자면

body {
  height: 100vh;
  background: radial-gradient(ellipse at bottom, #1b2735 0%, #090a0f 100%);
  overflow: hidden;
  filter: drop-shadow(0 0 10px white);
}

이 부분은 body 요소에 적용되는 스타일이다.

  • height를 100vh로 설정하여 화면 높이의 100%로 만든다.
  • radial-gradient를 사용하여 타원 형태로 배경을 그린다. 아래에서는 #1b2735에서 시작하여 #090a0f로 끝난다.
  • overflow: hidden;은 넘치는 부분을 감춘다.
  • filter: drop-shadow(0 0 10px white);은 하얀색 그림자를 만들어 화면에 그림자를 투영한다.
@function random_range($min, $max) {
  $rand: random();
  $random_range: $min + floor($rand * (($max - $min) + 1));
  @return $random_range;
}

이 부분은 Sass에서 사용되는 random_range 함수를 정의한다.

  • 이 함수는 min과 max라는 두 인수를 받는다.
  • random() 함수를 사용하여 0에서 1 사이의 난수를 생성한다.
  • 해당 난수를 주어진 범위 내로 스케일하고 이동시켜 최종적인 무작위 숫자를 생성한다.
  • 최종 값을 반환.
.snow {
  $total: 200;
  position: absolute;
  width: 10px;
  height: 10px;
  background: white;
  border-radius: 50%;

이 부분은 .snow 클래스를 가진 요소에 적용되는 스타일이다.

  • $total 변수를 사용하여 총 눈송이의 개수를 200으로 설정한다.
  • position, width, height, background, border-radius 등 각 눈송이에 공통으로 적용되는 스타일을 정의한다.
  @for $i from 1 through $total {
    $random-x: random(1000000) * 0.0001vw;
    $random-offset: random_range(-100000, 100000) * 0.0001vw;
    $random-x-end: $random-x + $random-offset;
    $random-x-end-yoyo: $random-x + ($random-offset / 2);
    $random-yoyo-time: random_range(30000, 80000) / 100000;
    $random-yoyo-y: $random-yoyo-time * 100vh;
    $random-scale: random(10000) * 0.0001;
    $fall-duration: random_range(10, 30) * 1s;
    $fall-delay: random(30) * -1s;

이 부분은 for 반복문을 사용하여 각 눈송이에 대한 스타일을 생성한다.

  • 각 눈송이에 대해 다양한 무작위 값들을 계산한다. 
    &:nth-child(#{$i}) {
      opacity: random(10000) * 0.0001;
      transform: translate($random-x, -10px) scale($random-scale);
      animation: fall-#{$i} $fall-duration $fall-delay linear infinite;
    }

nth-child 선택자를 사용하여 .snow 클래스를 가진 요소 중 특정 순서($i)의 요소에 적용되는 스타일을 정의한다.

  • opacity를 무작위 값으로 설정하고, 초기 위치와 크기를 지정한다.
  • animation 속성을 사용하여 무한히 반복되는 fall-#{$i} 애니메이션을 적용한다.
    @keyframes fall-#{$i} {
      #{percentage($random-yoyo-time)} {
        transform: translate($random-x-end, $random-yoyo-y) scale($random-scale);
      }

      to {
        transform: translate($random-x-end-yoyo, 100vh) scale($random-scale);
      }
    }

@keyframes를 사용하여 각 눈송이의 애니메이션을 정의한다.

  • 눈송이가 위에서 아래로 떨어지는 효과를 만듭니다. 이때 percentage($random-yoyo-time)을 사용하여 yoyo 효과를 부여한다.
    • "Yoyo 효과"는 움직임이 왕복(전진-후진)하는 애니메이션 효과를 말한다. 즉, 앞으로 나아가다가 어떤 지점에서 다시 뒤로 돌아오는 것을 의미한다. 이는 주로 왕복 운동을 흉내 내거나 반복적인 애니메이션에서 사용된다.

코드가 잘 적용되는지 확인하기 위해 React 프로젝트를 생성하여 scss, tsx 파일을 만들고 실행해봤더니

눈이 중간에서부터 떨어진다....

그래서 이걸 해결하기 위해 snowfall 컴포넌트가 화면 전체를 덮을 수 있도록 아래와 같은 css 속성을 지정해줬다.

.snow-wrapper {
  position: fixed;
  top: -20px;
  left: 0;
  width: 100%;
  height: 100%;
}

이렇게 해줬더니 위에서부터 눈이 잘 내린다😄

그리고 화면 왼쪽에 비해 오른쪽만 많이 내리는 듯한 느낌이 있어서 $random-x를 생성하는 부분에서 random(1000000)에서 0을 하나 빼줬더니 고르게 눈이 펑펑 잘 내린다.

 

그렇지만 아직 filter가 적용되지 않는 것 같길래 body에 있던 filter를 snow-wrapper로 옮기고 snow- wrapper의 z-index 값을 9999로 줬다. z-index가 큰 컴포넌트가 위쪽으로 오기 때문에 이렇게 하면 눈 내리는 효과를 담당하는 컴포넌트인 Snowfall가 가장 위로 오게 될 것이다.
그리고 화면 왼쪽에 비해 오른쪽만 많이 내리는 듯한 느낌이 있어서 $random-x를 생성하는 부분에서 random(1000000)에서 0을 하나 빼줬더니 고르게 눈이 펑펑 잘 내린다.👍