정의
스크롤을 내리다가 요소가 화면 안으로 들어오는 순간 스르륵 나타나게(fade/slide) 하되, 그걸 JavaScript 없이 CSS만으로 만들고 싶을 때 쓰는 기법이다.
핵심은 두 CSS 속성이다. animation-timeline: view()는 "이 애니메이션의 진행을 시간이 아니라 이 요소가 화면(viewport — 사용자에게 실제로 보이는 브라우저 표시 영역)에 얼마나 들어왔는지에 맞춰라"라는 뜻이다. animation-range: entry 0% entry 60%는 "요소가 화면에 막 들어오기 시작한 지점(entry 0%)부터 60%쯤 들어온 지점까지 애니메이션을 진행하라"는 뜻이다. 이 둘로, 요소가 뷰포트에 들어오는 구간에 맞춰 opacity(투명도)·transform(위치·크기 변형) 키프레임(keyframes — 애니메이션의 시작/중간/끝 상태를 정의한 것)을 매핑한다.
왜 필요한가
문제 상황: 같은 "스크롤하면 나타나기" 효과를 예전 방식으로 만들면, IntersectionObserver(요소가 화면에 들어왔는지 감지하는 JS API)로 감지하고 classList로 클래스를 붙이는 코드를 짜야 한다. 그러면 서버 렌더링 후 JS를 붙이는 hydration(서버가 만든 HTML에 React 같은 프레임워크가 이벤트를 붙여 실제로 동작하게 만드는 과정) 타이밍, 이펙트 정리, 그리고 애니메이션을 꺼야 하는 사용자 배려(reduced-motion) 코드까지 전부 손으로 관리해야 한다.
CSS view-timeline을 쓰면 이 로직이 선언적 CSS 몇 줄로 줄어든다. @supports(브라우저가 특정 CSS를 지원하는지 검사하는 조건 블록) 뒤에 두면, 지원하지 않는 브라우저에서는 애니메이션 없이 즉시 그대로 표시되고(내용이 사라지지 않음), 지원하는 브라우저에서만 은은한 등장 효과가 붙는다.
동작 원리
- 나타낼 요소에 타임라인과 범위를 지정한다.
@supports (animation-timeline: view())로 감싸, 미지원 브라우저는 이 규칙을 무시하고 요소를 그냥 보이게 둔다.- 애니메이션을 원치 않는 사용자를 위해
@media (prefers-reduced-motion: reduce)(운영체제에서 "동작 줄이기"를 켠 사용자를 감지하는 미디어 쿼리) 안에서animation: none으로 끈다. - 페이지 전체 진행바 같은 건 요소 진입이 아니라 문서 스크롤 전체를 기준으로 하는
scroll()타임라인을 쓴다 —view()(요소 단위)와 역할을 분리한다.
실무 적용
- 리스트 항목(
<li>), 통계 패널 같은 개별 콘텐츠 블록에만 붙인다. 페이지 전체 컨테이너에 걸면 진입 판정이 애매해진다. - 계속 반복되는 데모용 루프 애니메이션과는 클래스를 분리한다. 하나의 요소에 "스크롤 기준"과 "시간 기준" 타임라인을 섞으면 충돌한다.
- 움직이는 속성은
transform과opacity만 쓴다.width·top같은 레이아웃 속성을 애니메이션하면 매 프레임 레이아웃을 다시 계산하는 layout thrash(레이아웃 강제 재계산이 반복돼 성능이 떨어지는 현상)가 생긴다.
트레이드오프
- Safari·Chromium의 지원 범위는 넓어지는 추세지만 모든 브라우저 공통은 아니다 — 그래서
@supports감싸기가 사실상 필수다. - 진행 구간(range)을 너무 길게 잡으면 스크롤이 거의 끝날 때까지 애니메이션이 이어져 어색하다 — 그래서 보통 진입 60% 정도에서 끝내도록(entry 60%) 상한을 둔다.
사용하면 안 되는 경우
- 검색에 중요한 첫 화면(above-fold) 텍스트를 아예 숨기는 용도. 시작 투명도를 0.15 정도로 낮추는 건 괜찮지만,
display: none처럼 완전히 감추면 콘텐츠가 없는 것으로 취급될 위험이 있다.
흔한 실수
- 위치를 고정하는 부모(sticky)에
overflow: hidden을 걸어, 고정 동작과 등장 효과가 동시에 깨진다. - 반복 루프 키프레임을 붙인 클래스와 등장(view-reveal) 클래스를 같은 요소에 함께 걸어, 두 애니메이션이 서로를 덮어쓴다.
관련 개념
- scroll-driven-narrative-layout — 스크롤 진행에 맞춰 화면을 서사적으로 전개하는 상위 레이아웃 패턴
- cls-skeleton-layout-reservation — 등장 전 자리를 미리 잡아 레이아웃이 밀리지(CLS) 않게 하는 기법