View Transition은 애니메이션 효과가 아니라 상태 변화 계약이다
화면 전환이 부드러워 보이게 만드는 일과, 사용자가 이해할 수 있는 상태 변화 계약을 설계하는 일은 어떻게 다를까?
View Transition은 애니메이션 효과가 아니라 상태 변화 계약이다
- 카테고리: web_app_dev
- 예상 읽기 시간: 10분
- 오늘의 질문: 화면 전환이 부드러워 보이게 만드는 일과, 사용자가 이해할 수 있는 상태 변화 계약을 설계하는 일은 어떻게 다를까?
- 핵심 출처:
- Chrome 147 enables concurrent and nested view transitions with element-scoped view transitions - 2026-03-27, 확인일 2026-06-20
- What's new in View Transitions — 2025 update - 2025-10-08, 확인일 2026-06-20
- Smooth transitions with the View Transition API - 문서, 확인일 2026-06-20
- Using the View Transition API - MDN - 문서, 확인일 2026-06-20
<ViewTransition>– React - Canary/Experimental 문서, 확인일 2026-06-20- React Labs: View Transitions, Activity, and more - 2025-04-23, 확인일 2026-06-20
1. 왜 지금 봐야 하나
웹앱에서 “화면 전환”은 보통 마지막 장식처럼 취급된다. 기능이 동작하고 나서 시간이 남으면 fade, slide, skeleton을 붙이는 식이다. 그런데 최근 View Transition API의 흐름을 보면 이것을 단순한 시각 효과로만 보기 어렵다.
Chrome은 2026년 3월 Chrome 147에서 Element.startViewTransition() 기반의 element-scoped view transitions를 Stable로 소개했다. 기존 document.startViewTransition()이 문서 전체 전환을 다루는 느낌이었다면, 새 흐름은 특정 DOM 서브트리 안에서만 전환을 시작할 수 있게 한다. Chrome 글은 이 기능이 여러 전환을 동시에 실행하고, 전환을 중첩하며, position: fixed 같은 레이어링 문제를 줄이고, 페이지 나머지 부분은 계속 상호작용 가능하게 만든다고 설명한다.
동시에 React 쪽에서도 <ViewTransition>이 Canary/Experimental 채널 문서로 올라와 있다. React 문서는 이 API가 React Transitions, Suspense, 브라우저 View Transition API를 연결해 컴포넌트 트리를 애니메이션할 수 있게 한다고 설명한다. 단, React가 startViewTransition을 자동으로 호출하므로 React 안에서는 직접 호출하지 말라고 안내한다.
이 변화가 중요한 이유는 “예쁜 화면 전환을 쉽게 만들 수 있다”가 아니다. 웹앱의 상태 변화가 점점 복잡해졌기 때문이다. 서버 컴포넌트, optimistic update, Suspense, 데이터 캐시, 클라이언트 라우팅, 부분 업데이트가 섞이면 사용자는 “내가 방금 누른 것이 어디에 반영됐는지”를 놓치기 쉽다. View Transition은 이 혼란을 줄일 수 있지만, 잘못 쓰면 오히려 느린 화면을 가리고, 접근성을 해치고, 클릭 가능한 영역을 애니메이션 스냅샷 뒤에 숨길 수도 있다.
오늘의 관점은 이렇다. View Transition은 애니메이션 라이브러리 대체재가 아니라, 사용자가 상태 변화를 이해하도록 old UI와 new UI 사이의 관계를 명시하는 계약이다.
2. 핵심 개념
View Transition API의 핵심은 “DOM이 바뀌기 전후를 브라우저가 스냅샷으로 잡고, 그 사이를 CSS/웹 애니메이션으로 연결한다”는 것이다.
MDN과 Chrome 문서를 합쳐 보면 같은 문서 안의 SPA 전환은 대략 이렇게 움직인다.
document.startViewTransition(updateCallback)을 호출한다.- 브라우저가 현재 화면의 스냅샷을 캡처한다.
updateCallback안에서 DOM을 바꾼다.- 브라우저가 새 화면의 스냅샷을 만든다.
::view-transition-*pseudo-element 트리를 통해 old/new 스냅샷을 애니메이션한다.- 애니메이션이 끝나면 스냅샷이 제거된다.
기본 전환은 보통 root snapshot의 cross-fade다. 하지만 실제 제품에서는 “페이지 전체가 흐릿하게 바뀌는 것”보다 “상품 카드가 상세 이미지로 이어진다”, “필터링된 항목이 제자리에서 재배치된다”, “사이드바 안의 선택 목록만 바뀐다”가 더 중요하다. 그래서 view-transition-name으로 특정 요소를 별도 스냅샷으로 분리하고, ::view-transition-old(name), ::view-transition-new(name), ::view-transition-group(name) 같은 pseudo-element에 애니메이션을 준다.
여기서 바로 실무 함정이 나온다. view-transition-name은 동시에 렌더링된 요소마다 고유해야 한다. MDN은 같은 이름이 동시에 두 개 있으면 ViewTransition.ready가 reject되고 전환이 스킵될 수 있다고 설명한다. 리스트 아이템 100개를 움직일 때 이름 100개를 직접 관리하는 것은 버그를 부른다. 그래서 최근 흐름에서는 view-transition-name: match-element처럼 브라우저가 같은 문서 안의 요소 identity 기반으로 이름을 자동 부여하는 기능이 중요해졌다.
즉, View Transition의 기본 단위는 “애니메이션 효과”가 아니라 “이 상태 변화에서 어떤 요소가 이전 상태의 무엇과 연결되는가”다.
3. 최신 이슈와 연결
이번 주제로 볼 최신 포인트는 세 가지다.
첫째, Baseline과 브라우저 지원의 변화다. Chrome의 2025 업데이트는 same-document view transitions가 Interop 2025의 초점 중 하나였고, Firefox 144 지원으로 Baseline Newly available이 되는 흐름을 설명한다. Chrome 문서 기준 same-document transitions는 Chrome/Edge 111+, Safari 18+, Firefox 144+에서 다룰 수 있다. 반면 cross-document transitions는 같은 origin의 문서 간 이동에 @view-transition { navigation: auto; }로 opt-in하는 방식이며, 지원 범위와 제약이 다르다. 따라서 “View Transition이 된다/안 된다”가 아니라 “same-document인가, cross-document인가, 같은 origin인가, fallback은 있는가”를 구분해야 한다.
둘째, React가 전환 타이밍을 프레임워크 상태 모델과 연결하기 시작했다. React Labs 글은 View Transitions를 “what, when, how”로 설명한다. 무엇을 애니메이션할지는 <ViewTransition>으로 감싸고, 언제 애니메이션할지는 startTransition, useDeferredValue, Suspense fallback/content 전환 같은 React의 비동기 UI 전환이 결정하며, 어떻게 보일지는 CSS pseudo-selector나 class로 정한다. React 문서는 기본 setState는 <ViewTransition>을 활성화하지 않고, Transition/Suspense/deferred value 같은 업데이트가 활성화 조건이라고 설명한다.
셋째, Chrome 147의 element-scoped view transitions는 전체 문서 전환의 부작용을 줄이는 방향이다. Chrome 글에 따르면 Element.startViewTransition()은 특정 subtree에서 전환을 시작할 수 있다. 여러 리스트가 동시에 재정렬되거나, 바깥 레이아웃 전환과 안쪽 리스트 전환이 중첩되는 상황을 더 자연스럽게 다룰 수 있다. 제품 관점에서는 이것이 중요하다. 장바구니 사이드바, 검색 결과 그리드, 탭 패널처럼 “화면 일부만 바뀌어야 하는” UI에서 전체 페이지를 멈추는 전환은 사용자에게 방해가 된다.
4. 개발자 관점 해석
웹앱 개발자가 View Transition을 도입할 때 첫 질문은 “어떤 애니메이션을 넣을까?”가 아니다. 먼저 상태 변화의 종류를 나눠야 한다.
- 위치 변화: 정렬, 필터, 드래그 후 재배치처럼 같은 아이템이 다른 자리로 이동한다.
- 정체성 변화: 카드가 상세 페이지의 대표 이미지로 이어지는 것처럼 old element와 new element가 같은 개체를 가리킨다.
- 가시성 변화: 모달, 탭, 아코디언, 사이드바처럼 나타나고 사라진다.
- 데이터 신선도 변화: mutation 후 서버 데이터가 다시 읽히며 숫자나 상태가 바뀐다.
- 페이지 경계 변화: 라우트 이동 또는 same-origin 문서 이동이다.
이 분류 없이 루트 전체에 cross-fade를 걸면 사용자는 오히려 관계를 잃는다. 예를 들어 필터 버튼을 눌렀는데 전체 화면이 fade되면 어떤 항목이 사라졌고 어떤 항목이 남았는지 알기 어렵다. 반대로 각 카드가 자기 identity를 유지한 채 이동하면 사용자는 “필터링 때문에 재배치됐다”는 의미를 이해한다.
React 앱에서는 한 가지를 더 조심해야 한다. React 문서는 React <ViewTransition> 사용 시 React가 브라우저 startViewTransition을 자동 호출하므로 직접 호출하지 말라고 한다. 즉 React가 관리하는 UI 상태와 수동 DOM 전환 코드를 섞으면 전환이 중단되거나 타이밍이 꼬일 수 있다. React 안에서는 전환 타이밍을 startTransition, Suspense, router navigation과 맞추고, 수동 API는 React 밖의 독립 DOM 영역이나 프레임워크가 아직 관리하지 않는 UI에 제한하는 편이 안전하다.
또한 접근성은 선택 사항이 아니다. React 문서는 reduced motion을 자동으로 꺼주지 않으므로 prefers-reduced-motion에 맞춰 애니메이션을 줄이거나 끄라고 안내한다. View Transition은 스냅샷을 움직이는 기술이라 시각적으로는 부드러워도, 사용자가 빠른 클릭·키보드 탐색·스크린 리더 흐름에서 혼란을 겪을 수 있다. “전환이 예쁘다”보다 “전환 중에도 사용자가 무엇을 할 수 있는가”를 테스트해야 한다.
5. 내 프로젝트에 적용할 체크포인트
작은 웹앱 팀이라면 아래 순서로 점검해보자.
- 전환을 넣을 상태 변화 하나만 고른다. 전체 앱 라우팅보다 검색 결과 필터, 카드 → 상세, 사이드바 열기처럼 범위가 작은 UI가 좋다.
- old/new 관계를 말로 적는다. “이 카드의 썸네일은 상세 페이지의 hero 이미지와 같은 상품이다”처럼 설명할 수 있어야 한다.
- fallback을 먼저 둔다.
document.startViewTransition이 없으면 즉시 DOM을 업데이트해야 한다. 전환은 기능의 조건이 아니라 향상이어야 한다. - 이름 충돌을 피한다. 직접
view-transition-name을 붙인다면 동시에 같은 이름이 렌더링되지 않는지 확인한다. 같은 문서의 리스트 재정렬은match-element사용 가능성을 검토한다. - scope를 작게 잡는다. 페이지 전체 root cross-fade보다 특정 컨테이너, 카드, 리스트, 사이드바 단위가 제품 의미를 더 잘 보존한다.
- React에서는 수동 호출과 React
<ViewTransition>을 섞지 않는다. React Canary/Experimental을 쓰는 실험이라면 React 문서의 방식대로startTransition과<ViewTransition>을 맞춘다. - reduced motion과 입력 가능성을 테스트한다. 전환 중 클릭, 키보드 포커스, 빠른 연속 조작,
prefers-reduced-motion에서 동작을 확인한다. - 성능 지표를 숨기지 않는다. View Transition은 느린 데이터 fetch를 해결하지 않는다. 애니메이션으로 지연을 가리는 대신 loading, optimistic update, cache invalidation과 함께 설계한다.
6. 오늘 10분 액션
아래 실험은 실제 코드베이스에 바로 적용할 수 있다.
- 내 프로젝트에서 “상태 변화가 갑작스러워서 사용자가 놓치는 UI” 하나를 고른다. 예: 필터링되는 카드 리스트, 선택된 항목이 사이드바로 이동하는 흐름, 탭 전환.
- 그 UI에 대해 old state와 new state를 한 문장으로 적는다. “사용자가 A 필터를 켜면 같은 상품 카드들이 새 조건에 맞춰 재배치된다.”
- 브라우저 지원 fallback을 포함한 의사코드를 만든다.
function updateWithTransition(update: () => void) {
if (!document.startViewTransition) {
update();
return;
}
document.startViewTransition(() => {
update();
});
}
- React 실험이라면 수동 helper를 바로 쓰기보다, 해당 변화가
startTransition으로 감쌀 수 있는 UI 상태 변화인지 먼저 본다.
import { startTransition, ViewTransition } from 'react';
function ProductArea({ children }: { children: React.ReactNode }) {
return <ViewTransition default="product-area">{children}</ViewTransition>;
}
function onFilterChange(nextFilter: string) {
startTransition(() => {
setFilter(nextFilter);
});
}
- 마지막으로 이 질문에 답한다. “이 전환은 사용자가 관계를 이해하는 데 도움을 주는가, 아니면 느린 업데이트를 예쁘게 숨기는가?” 후자라면 애니메이션보다 데이터 흐름과 로딩 상태를 먼저 고쳐야 한다.
7. 더 볼 자료
- Chrome의 element-scoped view transitions 글은 Chrome 147에서 subtree 단위 전환이 왜 필요한지 보여준다.
- Chrome의 Smooth transitions with the View Transition API 문서는 same-document와 cross-document 전환의 차이를 빠르게 비교하기 좋다.
- MDN의 Using the View Transition API는 lifecycle, snapshot, pseudo-element tree를 확인할 때 유용하다.
- React의
<ViewTransition>문서는 React가 전환 타이밍을 어떻게 조율하는지, 왜 직접startViewTransition을 호출하지 말라고 하는지 확인하는 데 필요하다. - React Labs의 View Transitions, Activity, and more는
what / when / how모델로 React View Transition을 이해하기 좋다.
중복 회피 메모
로컬 content/generated와 Supabase 최근 web_app_dev 글을 확인했다. 최근 글은 Supabase 브랜칭과 pg-delta, 에이전트 친화적 content negotiation, React Compiler, Supabase AI 에이전트 권한표, Next.js Cache Components, 패스키/RLS/Realtime, Hono 보안 릴리스를 다뤘다. 이번 글은 React나 Next.js 성능/캐시/권한을 반복하지 않고, Chrome 147의 element-scoped view transitions와 React Canary <ViewTransition> 문서를 바탕으로 화면 전환을 “상태 변화 의미를 보존하는 UI 계약”으로 해석하는 데 집중했다.
핵심 출처
로그인하면 이 글을 북마크하고, 나만 보는 한 줄 메모를 남길 수 있어요.
댓글 0
최신순 ▾혹시 이 글을 읽는 동료 개발자가 있다면, GitHub으로 로그인하고 한 줄 흔적을 남겨줘요. (스팸 방지용 로그인이에요)