가이드/ 애니메이션
ac_unit

CSS 눈 내리는 효과: 순수 CSS 눈송이와 시즌 UI

눈 내리는 효과는 자바스크립트 라이브러리 없이 CSS 키프레임만으로 충분히 만들 수 있습니다. 핵심은 눈송이 하나를 잘 만드는 것이 아니라, 여러 개가 서로 달라 보이도록 흩뜨리는 것입니다. 그리고 몇 개까지가 안전한지 아는 것입니다.

2026년 7월 · 8분 분량

가장 단순한 눈송이 하나

"눈송이" 하나는 화면 위에서 아래로 떨어지면서 가로로 흘러가는 작은 흰 원입니다. 기본 구성 요소는 이렇습니다:

.snowflake {
  position: fixed;
  top: -10px;
  width: 8px;
  height: 8px;
  background: white;
  border-radius: 50%;
  opacity: 0.8;
  animation: fall 10s linear infinite;
  pointer-events: none;
}

@keyframes fall {
  0% {
    transform: translateY(0) translateX(0);
    opacity: 0.8;
  }
  100% {
    transform: translateY(110vh) translateX(20px);
    opacity: 0;
  }
}

110vh는 눈송이가 화면 아래로 완전히 빠져나가도록 보장합니다. 마지막에 불투명도를 낮추면 눈송이가 갑자기 사라지지 않습니다. position: fixed는 스크롤과 상관없이 콘텐츠 위에 떠 있게 합니다.

여러 눈송이 무작위화하기

그럴듯한 눈의 비결은 변화입니다. 시작 위치, 크기, 속도, 가로 흐름이 서로 달라야 합니다. 순수 CSS로도 요소별 커스텀 속성을 쓰면 됩니다:

<div class="snow">
  <span class="snowflake" style="--left:10%; --duration:8s; --delay:-2s; --size:6px; --drift:40px;"></span>
  <span class="snowflake" style="--left:30%; --duration:12s; --delay:-5s; --size:10px; --drift:-30px;"></span>
  <span class="snowflake" style="--left:50%; --duration:15s; --delay:-8s; --size:8px; --drift:50px;"></span>
  <span class="snowflake" style="--left:70%; --duration:10s; --delay:-3s; --size:12px; --drift:-20px;"></span>
  <span class="snowflake" style="--left:90%; --duration:13s; --delay:-6s; --size:7px; --drift:30px;"></span>
</div>

<style>
.snowflake {
  position: fixed;
  top: -20px;
  left: var(--left);
  width: var(--size);
  height: var(--size);
  background: white;
  border-radius: 50%;
  opacity: 0.8;
  animation: fall var(--duration) linear infinite;
  animation-delay: var(--delay);
  pointer-events: none;
}

@keyframes fall {
  0%   { transform: translateY(0) translateX(0); opacity: 0.8; }
  100% { transform: translateY(110vh) translateX(var(--drift)); opacity: 0; }
}
</style>

animation-delay에 음수 값을 주면 각 눈송이가 애니메이션 도중부터 시작합니다. 그래서 첫 눈송이가 바닥에 닿기까지 10초를 기다리지 않고, 페이지가 열리는 순간부터 눈이 내리고 있습니다.

자연스러운 흔들림 더하기

실제 눈은 직선 대각선이 아니라 곡선을 그리며 흩날립니다. 키프레임 중간 단계를 넣어 흔들림을 만듭니다:

@keyframes fall {
  0%   { transform: translateY(0) translateX(0); }
  25%  { transform: translateY(25vh) translateX(20px); }
  50%  { transform: translateY(55vh) translateX(-15px); }
  75%  { transform: translateY(80vh) translateX(10px); }
  100% { transform: translateY(110vh) translateX(-5px); opacity: 0; }
}

linear 대신 ease-in-out을 쓰면 방향이 바뀌는 지점에서 부드럽게 가속합니다. 여러 개의 X 오프셋이 만드는 지그재그가 바람에 흩날리는 느낌으로 읽힙니다.

크기 변화로 깊이 만들기

모두 같은 속도와 같은 크기로 떨어지는 눈은 가짜처럼 보입니다. 이렇게 원근을 흉내 냅니다:

  • 큰 눈송이는 빠르게 떨어집니다 (보는 사람에게 가까움)
  • 작은 눈송이는 느리게 떨어지고 더 투명합니다 (멀리 있음)
  • 먼 눈송이는 살짝 흐리게 처리합니다. 작은 크기에 filter: blur(1px)을 주면 피사계 심도처럼 읽힙니다
  • 4px에서 14px 사이로 크기를 섞으세요. 눈송이 요소마다 다른 값을 주면 화면이 단조로워지지 않습니다

성능 예산

눈송이 애니메이션 하나하나가 GPU 자원을 씁니다. 현실적인 한계는 이렇습니다:

  • 30~50개 — 어떤 기기에서도 문제없습니다. 대부분의 사이트에는 이 정도면 충분합니다.
  • 50~150개 — 데스크톱에서는 괜찮지만 오래된 모바일 기기에서는 끊길 수 있습니다.
  • 150개 이상 — CSS가 버거워지기 시작합니다. Canvas API를 고려하세요.
  • 움직임에는 반드시 transform을 쓰세요. top이나 left는 레이아웃을 다시 계산하게 만듭니다.
  • will-change: transform을 추가하되, 시즌이 끝나면 반드시 제거하세요.
  • prefers-reduced-motion을 존중하세요. 모션을 꺼 둔 사용자에게 눈은 반가운 효과가 아닙니다.
@media (prefers-reduced-motion: reduce) {
  .snowflake {
    animation: none;
    display: none;
  }
}

다른 스타일

유니코드 눈송이 문자

단순한 원 대신 모양이 있는 눈송이를 쓰려면 span 안에 유니코드 문자를 넣습니다:

<span class="snowflake">❄</span> /* 기본 눈송이 */
<span class="snowflake">❆</span> /* 더 굵은 형태 */
<span class="snowflake">✻</span> /* 육각 별 */

<style>
.snowflake {
  font-size: var(--size);
  color: white;
  background: transparent;
  border-radius: 0;
  width: auto;
  height: auto;
}
</style>

그라디언트 배경 흐림

파티클 없이 더 은은하게 겨울 느낌을 내는 방법입니다. 화면 위쪽의 방사형 그라디언트가 차가운 파란색으로 번지면, 애니메이션 비용 없이 겨울 분위기만 남습니다.

Canvas로 넘어가야 할 때

CSS 기반 눈은 파티클 100~150개 근처에서 한계에 부딪힙니다. 더 사실적인 효과가 필요하다면:

  • 파티클이 많을 때 (200개 이상) — Canvas 2D나 WebGL은 수천 개도 부드럽게 처리합니다
  • 실제 물리 — 바람의 힘, 충돌, 표면에 쌓이는 눈
  • 눈 쌓임 — 바닥이나 요소 위에 멈춰서 쌓이는 파티클
  • 상호작용 — 마우스 위치에 반응하는 파티클
  • 원이 아닌 정교한 눈송이 — PNG 텍스처나 절차적으로 생성한 SVG 눈송이

Particles.js, tsparticles 같은 라이브러리나 직접 작성한 Canvas 코드가 이런 경우를 감당합니다. 효과가 은은한 장식일 때만 CSS 눈을 쓰고, 화면의 주인공일 때는 Canvas를 쓰세요.

시즌에만 켜기

/* 12월과 1월에만 눈을 표시 */
<script>
  const month = new Date().getMonth(); /* 0-11 */
  if (month === 11 || month === 0) {
    document.body.classList.add('snowing');
  }
</script>

<style>
.snow { display: none; }
body.snowing .snow { display: block; }
</style>

자주 묻는 질문

눈 효과가 SEO나 성능 점수에 해가 되나요?
적당한 양의 CSS 눈(파티클 30~50개)은 Core Web Vitals에 거의 영향을 주지 않습니다. 흔들림까지 넣은 무거운 눈(100개 이상)은 모바일에서 INP 점수를 떨어뜨릴 수 있습니다. 배포 전에 Lighthouse로 측정하고, 점수가 내려가면 파티클 수를 줄이거나 prefers-reduced-motion으로 끄세요.
모든 페이지에 넣어도 되나요, 아니면 홈에만 넣어야 하나요?
홈과 랜딩 페이지에만 쓰세요. 사이트 전체에 눈이 계속 내리면 금방 성가셔집니다. 사용자는 더 이상 눈을 인지하지 않으면서 배터리만 소모합니다. 전체에 넣고 싶다면 끄는 버튼을 함께 제공하세요.
순수 CSS로 만들 수 있는 다른 계절 효과는 무엇인가요?
낙엽(가을)은 잎 문자를 쓰고 가로 흐름을 더 넓게 잡습니다. 비는 가늘고 긴 흰 사각형을 더 빠르게 떨어뜨립니다. 색종이는 여러 크기의 색깔 사각형입니다. 불꽃놀이는 CSS로는 어렵고 보통 Canvas가 필요합니다.
모바일에서만 눈을 숨기려면 어떻게 하나요?
미디어 쿼리를 쓰세요. @media (max-width: 640px) { .snow { display: none; } }. 애니메이션 비용이 더 큰 모바일에서 배터리를 아낍니다. 완전히 없애는 대신 모바일에서 파티클 수만 줄이는 방법도 있습니다.
특정 영역 안에만 눈을 내리게 할 수 있나요?
가능합니다. 눈 컨테이너를 해당 섹션 안에 넣고 position: fixed 대신 섹션 기준의 position: absolute를 씁니다. 낙하 높이를 섹션 높이에 맞추면 됩니다. 배너 영역에만 눈이 내리는 히어로 섹션에 유용합니다.

무료 참고 자료

47가지 도구 치트 시트

이 사이트의 모든 도구와 각각의 용도, 사용 시점을 한 장에 정리했습니다. 무료입니다. 도구와 달리 파일 전송을 위해 Gumroad가 이메일을 요청합니다.