프론트엔드의 성능과 UX는 균형의 문제
좋은 UX는 단순히 화려한 인터랙션이 아니라 사용자가 자연스럽고
즉각적으로 반응하는 인터페이스를 경험하게 만드는 것,
CSS 애니메이션을 과도하게 사용하면 CPU 사용량이 폭등하고
부드러운 전환 효과를 위해 JS 애니메이션을 구현하면
메인 스레드가 막힐 수 있다.
반대로 애니메이션을 제거할수록 기계적인 UI로 체감하게 된다.
결국, 성능과 UX는 균형의 문제다.
애니메이션이 UX에 주는 실제 효과
맥락 유지(Context)
새 페이지로 전환될 때 부드러운 Fade 효과가 있다면 사용자는 “화면이 바뀌었다”를 인지하면서도 집중이 끊기지 않는다.피드백(Feedback)
클릭 시 버튼이 살짝 눌리는 Motion은 사용자의 액션이 “인식되었다”는 시각적 신호다.주의 유도(Attention)
중요 요소(알림, 오류, 강조 영역)를 시선이 자연스럽게 따라가게 만든다.
브라우저 렌더링 파이프라인에 답이 있다
브라우저는 화면을 다음 단계에 거쳐 그린다.
JavaScript → Style/Layout → Paint → Composite
이때, Layout과 Paint 단계에서 CPU 연산이 무거워진다.
따라서 애니메이션은 Layout / Paint 를 피하고
Composite 단계만 사용해야 한다.
GPU 가속 애니메이션
가장 가벼운 애니메이션은 transform과 opacity를 사용하는 것이다.
- transform: translate(), scale(), rotate()
- opacity: 0 → 1
이 속성들은 GPU에서 합성(Compositing)만 수행하므로
Layout / Paint를 건너뛴다.
→ 레이아웃 재계산이 없고, 초당 60프레임을 유지하기 쉽다.
.card {
transition: transform 0.3s ease, opacity 0.3s ease;
}
.card:hover {
transform: translateY(-4px);
opacity: 0.9;
}
작은 차이지만, CPU가 아닌 GPU가 처리하게 하면 전력 소모도 줄고,
모바일 기기에서 부드럽게 동작한다.
Repaint / Reflow를 유발하는 속성 피하기
다음 속성들은 Layout, Paint 단계를 다시 돌려 성능을 저하시킨다.
- top / left / width / height → 레이아웃 전체 재계산(Reflow)
- box-shadow, borderRadius → 픽셀 다시 그림(Paint)
- filter, backdrop-filter → GPU 처리 가능하지만 비용 높음
*Chrome DevTools → Performance 탭에서 “Paint flashing”을 켜면
어떤 요소가 자주 다시 그려지는지 시각화할 수 있다.
requestAnimationFrame으로 JS 애니메이션 제어
setInterval은 브라우저 프레임과 동기화되지 않아 끊김이 발생한다.
반면 requestAnimationFrame은 브라우저의 리페인트 주기(보통 60Hz) 에 맞춰 콜백을 호출한다.
function fadeIn(el) {
let opacity = 0;
function tick() {
opacity += 0.05;
el.style.opacity = opacity;
if (opacity < 1) requestAnimationFrame(tick);
}
requestAnimationFrame(tick);
}
→ GPU 기반 CSS 애니메이션과 함께 쓰면 부드럽고 자연스러운 UX를 구현할 수 있다.
애니메이션과 접근성(A11y)
시각적 효과가 항상 긍정적인 것은 아니고,
일부 사용자(특히 어지럼증, 민감한 시각 반응을 가진 이들)는
모션에 불편함을 느낀다.
@media (prefers-reduced-motion: reduce) {
* {
animation: none !important;
transition: none !important;
}
}
→ 시스템 설정에서 “애니메이션 줄이기”를 켠 사용자는
자동으로 정적인 UI를 경험한다.
좋은 UX란, 모든 사용자에게 적절한 경험을 제공하는 것이다.
애니메이션 최적화 전략
- FPS 유지 → transform / opacity 중심 애니메이션
- CPU 부하 감소 → requestAnimationFrame, GPU 레이어 활용
- UX 피로도 완화 → 150~300ms 이내 전환, Easing 자연스럽게.
- 접근성 보장 → prefers-reduced-motion 지원
- 리소스 관리 → 비가시 요 애니메이션 일시정지(IntersectionObserver)