알림 배지 펄스 애니메이션이 무한 반복되는 원리

알림 아이콘이나 장바구니 배지가 심장 박동처럼 커졌다 작아지길 끝없이 반복하는 걸 본 적 있을 것입니다. 자바스크립트 타이머가 계속 돌고 있을 것 같지만, 실제로는 CSS 몇 줄만으로 완성됩니다. 무한히 반복되는 원리를 알면 어떤 아이콘에도 같은 효과를 직접 붙일 수 있습니다.
요약 ① 애니메이션이 끝없이 반복되는 건 자바스크립트 타이머가 아니라 CSS의 animation-iteration-count: infinite 값 때문입니다 ② 커졌다 작아지는 동작은 @keyframes 안에 0%부터 100%까지 구간별 scale 값을 정해두면 브라우저가 그 사이를 자동으로 이어서 그려주는 원리입니다 ③ 실제 심장박동처럼 두 번 튀는 느낌은 하나의 반복 주기 안에 확대 지점을 두 번(작게 한 번, 크게 한 번) 넣어서 만듭니다
알림 배지는 왜 자바스크립트 없이도 계속 뛸까
이 움직임이 setInterval 같은 자바스크립트 타이머로 만들어졌을 거라 생각하기 쉽지만, 실제로는 CSS의 animation 속성 하나로 끝납니다. @keyframes로 0%부터 100%까지 구간별 모양을 정해두면, 브라우저가 그 사이를 알아서 부드럽게 이어줍니다.
핵심은 animation-iteration-count라는 값입니다. 기본값은 1이라 애니메이션이 한 번 재생되고 멈추지만, 이 값을 infinite로 지정하면 재생이 끝날 때마다 브라우저가 자동으로 처음부터 다시 실행합니다. 자바스크립트가 반복을 챙길 필요가 없는 이유입니다.
게다가 transform: scale로 만든 확대·축소는 레이아웃 계산과 무관한 그래픽 레이어에서 처리됩니다. 페이지의 다른 스크립트가 바쁘게 돌고 있어도 배지가 끊김 없이 계속 뛰는 것도 이 때문입니다.
다만 반복만으로는 심장 박동 같은 느낌이 나지 않습니다. 실제 맥박은 한 번의 주기 안에서 작게 한 번, 크게 한 번 튀는 두 번의 움직임으로 이루어져 있습니다. 이 리듬은 반복 설정이 아니라 keyframes 안의 구간을 몇 개로 나누느냐에 달려 있습니다.
확인하는 방법 — 직접 keyframes로 펄스 만들기
가장 단순한 펄스는 세 구간이면 충분합니다. 0%에서 원래 크기(scale(1))로 시작해 50%에서 살짝 커졌다가(scale(1.2)) 100%에서 다시 원래 크기로 돌아오게 적으면 됩니다.
이 keyframes를 요소에 걸려면 animation 속성 하나면 됩니다. animation: pulse-basic 1.2s ease-in-out infinite;처럼 이름, 재생 시간, 가속도 함수, 반복 횟수를 순서대로 적으면 되고, infinite 자리에 자바스크립트는 전혀 필요하지 않습니다.
심장 박동처럼 두 번 튀는 느낌을 내려면 하나의 주기 안에 확대 지점을 두 번 넣어야 합니다. 0%는 원래 크기, 14%에서 작게 한 번, 28%에서 다시 원래 크기, 42%에서 크게 한 번, 70%부터는 다음 박동까지 원래 크기를 유지하는 식입니다.
이렇게 구간을 나누면 '작게 한 번 - 크게 한 번 - 쉼' 패턴이 한 주기 안에 완성되고, infinite가 이 주기 전체를 계속 반복시켜 실제 맥박과 비슷한 리듬을 만들어냅니다. 확대 폭이나 재생 시간을 바꾸면 리듬의 느낌도 함께 달라집니다.
저희 도구로 확인하기. 구간별 퍼센트와 scale 값을 손으로 맞추는 대신, 프리셋을 고르고 슬라이더만 움직이면 같은 원리의 keyframes 코드가 바로 만들어집니다.
무료 · 가입 불필요 · 프리셋 선택 후 CSS 코드 바로 복사

자주 막히는 지점
| 상황 | 원인/해결 |
|---|---|
| 애니메이션이 한 번만 재생되고 멈춤 | animation-iteration-count 기본값이 1이기 때문 — infinite로 지정해야 계속 반복됩니다 |
| 커졌다 작아질 때 중심이 아니라 한쪽으로 쏠림 | 요소나 부모의 레이아웃(정렬 방식) 때문에 확대 기준점이 어긋난 경우입니다 |
| 확대된 부분이 잘려서 보임 | 배지를 감싼 부모 요소에 overflow: hidden이 걸려 있는지 확인해야 합니다 |
| 심장 박동처럼 두 번 안 뛰고 한 번만 뛰는 것처럼 보임 | keyframes 구간이 0%·50%·100% 세 개뿐인 단순 펄스 형태이기 때문 — 중간 구간을 추가해야 합니다 |
표에서 보듯 대부분의 문제는 반복 횟수나 부모 요소의 overflow 설정, keyframes 구간 개수를 놓쳐서 생깁니다. 하나씩 확인하면 대부분 바로 해결됩니다.
정리
알림 배지가 끝없이 뛰는 건 자바스크립트 타이머가 아니라 animation-iteration-count: infinite 하나의 힘입니다. 커졌다 작아지는 움직임은 @keyframes 구간별 scale 값으로, 심장 박동 같은 두 번 튀는 리듬은 한 주기 안에 확대 지점을 두 번 넣는 구성으로 만들어집니다.
원리를 알면 퍼센트 구간과 scale 값을 직접 조정해서 원하는 리듬을 만들 수 있습니다. 매번 값을 손으로 계산하고 싶지 않다면 프리셋에서 시작해 슬라이더로 미세 조정하는 편이 빠릅니다.
무료 · 가입 불필요 · 프리셋 선택 후 CSS 코드 바로 복사
자주 묻는 질문
애니메이션을 한 번만 재생하고 멈추게 할 수 있나요?
네, animation-iteration-count 값을 infinite 대신 원하는 횟수(예: 3)로 지정하면 그만큼만 재생되고 멈춥니다. 특정 이벤트가 발생했을 때만 실행하고 싶다면 평소에는 클래스를 빼두었다가 필요할 때만 붙여주면 되고, 반복 자체는 여전히 CSS가 담당합니다.
width나 height를 키우는 방식과 transform: scale은 뭐가 다른가요?
width나 height를 바꾸면 레이아웃 재계산(리플로우)이 일어나서 프레임마다 부담이 크고 주변 요소 위치까지 흔들릴 수 있습니다. transform: scale은 레이아웃에 영향을 주지 않는 그래픽 레이어에서만 처리되어 배지처럼 자주 움직이는 요소에 적합합니다.
심장박동 프리셋과 기본 펄스는 어떤 차이가 있나요?
기본 펄스는 한 주기 안에서 한 번만 커졌다 작아지는 단순한 곡선이고, 심장 박동 프리셋은 한 주기 안에 작은 확대와 큰 확대를 순서대로 넣어 실제 맥박처럼 두 번 튀는 느낌을 재현합니다.
