CSS 배경 애니메이션 효과 모음 9종 — 한 줄 복붙으로
CSS 배경 애니메이션 효과 모음은 눈·별·비·컨페티·거품·반딧불이·꽃잎·안개처럼 작은 조각 여러 개를 화면에 흩뿌려 각자 다른 자리에서 계속 움직이게 만드는 CSS 기법입니다.
자동 재생 · 눌러서 해당 항목으로 · 전부 한 zip
아홉 개는 화려한 순서가 아니라 조각이 움직이는 방향 순으로 놓았습니다. 위에서 아래로 떨어지는 것(01·04·05·08), 제자리에서 반짝이거나 옆으로 흐르는 것(02·03), 아래에서 위로 뜨는 것(06), 제자리를 맴도는 것(07), 화면 전체가 왕복하는 것(09) 순서입니다. 항목마다 코드는 조각을 몇 개 어떻게 흩뿌렸는지가 핵심이라, 그 부분만 실었고 전체 파일은 zip에 있습니다.
01눈 내리는 효과
원 span 24개가 화면 위쪽 바깥에서 시작해 translateY로 천천히 떨어집니다. 연말 프로모션이나 겨울 이벤트 히어로 배경에 씁니다.
.p {
position: absolute; top: -8%; left: 0;
width: 6px; height: 6px; border-radius: 50%;
animation: fall 6s linear infinite;
animation-delay: calc(var(--i) * -0.28s);
}
@for $i from 1 through 24 {
.p:nth-child(#{$i}) { left: #{($i * 53) % 97}%; }
}
@keyframes fall {
0% { transform: translateY(0); opacity: 0; }
100% { transform: translateY(340px); opacity: 0; }
}
02별 반짝임
점 span 24개가 화면에 흩뿌려진 채 각자 다른 지연으로 밝아졌다 어두워집니다. 다크 모드 히어로나 밤 테마 이벤트 페이지에 씁니다.
.p {
position: absolute; width: 5px; height: 5px; border-radius: 50%;
box-shadow: 0 0 10px rgba(23, 20, 26, .55);
animation: twinkle 1.8s ease-in-out infinite;
animation-delay: calc(var(--i) * -0.31s);
}
@keyframes twinkle {
0%, 100% { transform: scale(.7); opacity: .2; }
50% { transform: scale(1.3); opacity: 1; }
}
03SVG 물결
같은 물결 모양을 두 장 이어붙여 폭 200%인 띠를 만들고 translateX로 절반만큼 옮기면 이어붙인 자리가 서로 같은 그림이라 이음새 없이 흐릅니다. 제품 소개 섹션의 하단 구분선이나 여행 랜딩 배경에 씁니다.
.layer { position: absolute; left: 0; right: 0; bottom: 0; display: flex; width: 200%; }
.wave { width: 50%; flex: none; }
.layer--back { animation: drift 6s linear infinite; }
.layer--front { animation: drift 3.9s linear infinite; }
@keyframes drift {
from { transform: translateX(0); }
to { transform: translateX(-50%); }
}
04비 내리는 효과
가는 선 span 22개가 12도 기울어진 채 대각선으로 빠르게 떨어집니다. 장마철 프로모션이나 날씨 앱 소개 화면에 씁니다.
.p {
position: absolute; top: -12%; width: 2px; height: 22px;
transform: rotate(12deg);
animation: rain .6s linear infinite;
animation-delay: calc(var(--i) * -0.07s);
}
@keyframes rain {
0% { transform: translateY(0) translateX(0) rotate(12deg); opacity: .7; }
100% { transform: translateY(380px) translateX(60px) rotate(12deg); opacity: .3; }
}
05컨페티 낙하
사각 조각 26개가 떨어지며 동시에 회전합니다. 절반은 시계 방향, 절반은 반시계 방향으로 돌고 3개마다 색이 바뀝니다. 결제 완료나 회원가입 완료 축하 화면에 씁니다.
.p { position: absolute; top: -10%; width: 7px; height: 11px; }
.p:nth-child(3n) { background: #2f6df6; }
@keyframes confetti {
0% { transform: translateY(0) rotate(0deg); opacity: 0; }
100% { transform: translateY(360px) rotate(var(--spin, 360deg)); opacity: .85; }
}
06거품 상승
테두리만 있는 원 20개가 화면 아래에서 위로 떠오르며 중간에 커졌다 작아집니다. 음료·주류 브랜드 히어로나 워터파크 소개 배경에 씁니다.
.p {
position: absolute; bottom: -10%; width: 10px; height: 10px;
border: 1.5px solid currentColor; border-radius: 50%;
animation: rise 4s cubic-bezier(.2, .8, .2, 1) infinite;
}
@keyframes rise {
0% { transform: translateY(0) scale(.6); opacity: 0; }
55% { transform: translateY(-170px) scale(1.15); }
100% { transform: translateY(-360px) scale(.8); opacity: 0; }
}
07반딧불이
흐릿한 점 16개가 깜빡이는 동시에 짧게 방향을 바꾸며 떠다녀, 불규칙한 빛의 궤적을 만듭니다. 자연·캠핑 브랜드 배경이나 감성 포트폴리오 히어로에 씁니다.
.p {
position: absolute; width: 4px; height: 4px; border-radius: 50%;
box-shadow: 0 0 12px rgba(255, 247, 230, .8);
animation: drift 3.5s ease-in-out infinite;
}
@keyframes drift {
0% { transform: translate(0, 0); opacity: 0; }
35% { transform: translate(14px, -10px); opacity: .9; }
55% { transform: translate(-8px, -20px); opacity: .3; }
100% { transform: translate(0, 0); opacity: 0; }
}
08벚꽃잎 흩날림
타원 18개가 낙하하며 회전과 좌우 흔들림을 더해, 바람에 나부끼며 떨어지는 꽃잎처럼 움직입니다. 봄 시즌 프로모션이나 웨딩·뷰티 브랜드 히어로에 씁니다.
.p { position: absolute; top: -10%; width: 10px; height: 6px; border-radius: 50%; }
@keyframes petal {
0% { transform: translate(0, 0) rotate(0deg); opacity: 0; }
30% { transform: translate(18px, 110px) rotate(120deg); }
60% { transform: translate(-14px, 240px) rotate(240deg); }
100% { transform: translate(10px, 380px) rotate(360deg); opacity: .3; }
}
09안개 흐름
폭 넓고 흐릿한 띠 3장이 같은 속도로 좌우 왕복하되 시작 시점만 서로 달라 겹치고, opacity도 함께 오가며 숨 쉬는 안개층을 만듭니다. 미스터리 콘텐츠 히어로나 산악 아웃도어 브랜드 배경에 씁니다.
.p {
position: absolute; left: -20%; width: 140%; height: 34%;
filter: blur(6px);
animation: driftx 2s linear infinite alternate;
}
.p:nth-child(2) { animation-delay: -0.66s; }
.p:nth-child(3) { animation-delay: -1.32s; }
@keyframes driftx {
from { transform: translateX(-30%); opacity: .18; }
to { transform: translateX(30%); opacity: .42; }
}
어디서 깨지는가 — 함정 셋
첫 번째 함정은 transform: translate()의 %가 스테이지가 아니라 요소 자신의 크기를 기준으로 계산된다는 점입니다. 눈·비·컨페티·거품·꽃잎 다섯 개를 처음 만들 때 translateY(370%)처럼 썼더니 6~22px 밖에 안 움직여 눈에 거의 안 보였습니다. px 값으로 바꾸고 나서야 화면을 실제로 가로질렀습니다.
두 번째는 블러를 세게 줄수록 오히려 안 보인다는 점입니다. 가장자리가 흐려지면 전이 구간이 넓어져, 한 프레임 사이에 바뀌는 픽셀 값의 차이가 판정용 픽셀 문턱을 못 넘을 수 있습니다. 09를 blur(16px)과 opacity만으로 처음 만들었을 때 누적면적은 94%까지 나왔지만(첫 프레임과 비교하면 결국 다 달라지니까) 강도와 움직인 프레임은 0이었고, 블러를 줄이고 이동 폭을 키우고 나서야 진짜 움직임으로 잡혔습니다.
세 번째는 애니메이션 길이와 이징의 조합입니다. ease-in-out처럼 시작과 끝이 느린 이징에 캡처 구간보다 훨씬 긴 지속 시간을 주면, 화면이 거의 정지한 것처럼 보입니다. 09를 처음 10초로 만들었을 때 실제로 그랬고, 지속 시간을 짧게 줄이자 흐름이 제대로 보였습니다. 위 세 함정을 이미 고쳐 둔 아홉 개 파일은 압축해서 zip으로 묶었고, 여는 비밀번호는 fjv3dy5x입니다.
접근성
운영체제의 동작 줄이기 설정을 켠 방문자에게는 아홉 개 조각 전부 prefers-reduced-motion: reduce 블록이 걸립니다. 01·04·05·08은 낙하를 멈추고 옅은 색만 남기고, 02·07은 반짝임·이동을 멈추고 고정 opacity만 남기며, 03·09는 흐름 자체를 멈춰 정지 이미지로 보여줍니다. 06은 상승을 멈추고 제자리 거품만 남깁니다. 움직임은 끄되 조각이 거기 있다는 사실은 남기는 게 원칙입니다.
@media (prefers-reduced-motion: reduce) {
.p { animation: none; opacity: .35; }
}
prefers-reduced-motion 자체의 브라우저별 지원 표는 MDN 문서에 정리돼 있습니다. 배경·입자 말고 다른 CSS 주제를 찾는다면 CSS 애니메이션 카테고리를 둘러보시고, 이 사이트를 처음 보셨다면 소개부터 읽어보세요.
FAQ
요소를 몇 개까지 흩뿌려도 되나요?
이 편은 항목당 3~26개를 씁니다. 40개를 넘기면 transform·opacity만 쓰더라도 합성해야 할 레이어가 늘어나 저사양 기기에서 버벅일 수 있습니다. 배경용이라면 20~30개 선에서 충분히 촘촘해 보이고, 그 이상은 눈에 띄는 차이가 크지 않습니다.
JS 없이 요소마다 다른 속도를 어떻게 주나요?
SCSS @for로 nth-child마다 서로 다른 곱수의 나머지를 계산해 위치·크기·지속 시간을 고정값으로 박아 넣습니다. --i 커스텀 프로퍼티는 animation-delay에만 써서 같은 애니메이션이 요소마다 다른 시점에서 시작하게 만듭니다. 둘 다 컴파일·렌더 시점에 끝나는 계산이라 런타임 JS가 필요 없습니다.
벚꽃잎이 파란색인 이유가 뭔가요?
이 사이트의 데모 색 팔레트에 분홍이 없어서 $subject-blue로 대신했습니다. zip을 열면 SCSS 변수 $color 하나만 바꿔서 원하는 색으로 즉시 바꿀 수 있습니다.