라우팅 규칙 전환 애니메이션은 Angular 애플리케이션의 여러 뷰 사이를 이동할 때 화면을 부드럽게 전환해서 사용자 경험을 개선합니다. Angular 라우터는 브라우저의 View Transitions API를 기본으로 지원하므로, 지원되는 브라우저에서 라우팅 규칙이 바뀔 때 매끄러운 애니메이션을 적용할 수 있습니다.
참고: 라우터의 네이티브 View Transitions 통합 기능은 현재 개발자 프리뷰입니다. 네이티브 View Transitions는 비교적 새로운 브라우저 기능이므로 모든 브라우저에서 지원되지는 않습니다.
View Transitions의 동작 방식
뷰 전환은 브라우저의 기본 document.startViewTransition API를 사용해서 애플리케이션의 여러 상태 사이를 부드럽게 전환합니다.
이 API는 다음과 같이 동작합니다.
- 현재 상태 캡처 — 브라우저가 현재 페이지의 스크린샷을 찍습니다.
- DOM 갱신 실행 — 콜백 함수가 실행되어 DOM을 갱신합니다.
- 새 상태 캡처 — 브라우저가 갱신된 페이지 상태를 캡처합니다.
- 전환 재생 — 브라우저가 이전 상태와 새 상태 사이의 애니메이션을 재생합니다.
startViewTransition API의 기본 구조는 다음과 같습니다.
document.startViewTransition(async () => {
await updateTheDOMSomehow();
});
브라우저 API의 자세한 내용은 Chrome 설명 문서를 참고하세요.
라우터의 뷰 전환 사용 방식
Angular 라우터는 내비게이션 라이프사이클에 뷰 전환을 통합해서 라우팅 규칙을 매끄럽게 전환합니다. 내비게이션 중 라우터는 다음과 같이 동작합니다.
- 내비게이션 준비 완료 — 라우팅 규칙 매칭, 지연 로딩, 가드, 리소스, 리졸버를 실행합니다.
- 뷰 전환 시작 — 라우팅 규칙 활성화 준비가 끝나면 라우터가
startViewTransition을 호출합니다. - DOM 갱신 — 전환 콜백 안에서 새 라우팅 규칙을 활성화하고 이전 라우팅 규칙을 비활성화합니다.
- 전환 마무리 — Angular가 렌더링을 완료하면 전환 Promise가 이행됩니다.
라우터의 뷰 전환 통합은 점진적 향상 방식으로 동작합니다. 브라우저가 View Transitions API를 지원하지 않으면 라우터는 애니메이션 없이 일반적인 DOM 갱신을 수행하므로, 애플리케이션이 모든 브라우저에서 동작할 수 있습니다.
라우터에서 View Transitions 활성화하기
라우터 설정에 withViewTransitions 기능을 추가하면 뷰 전환을 활성화할 수 있습니다.
Angular는 독립형 방식과 NgModule 방식의 부트스트랩을 모두 지원합니다.
독립형 부트스트랩
import {bootstrapApplication} from '@angular/platform-browser';
import {provideRouter, withViewTransitions} from '@angular/router';
import {routes} from './app.routes';
bootstrapApplication(MyApp, {
providers: [provideRouter(routes, withViewTransitions())],
});
NgModule 부트스트랩
import {NgModule} from '@angular/core';
import {RouterModule} from '@angular/router';
@NgModule({
imports: [RouterModule.forRoot(routes, {enableViewTransitions: true})],
})
export class AppRouting {}
이 예제는 카운터를 갱신할 때 startViewTransition을 직접 호출하는 대신 라우터 내비게이션을 사용하는 방법을 보여줍니다.
CSS로 전환 효과 조정하기
CSS로 뷰 전환을 조정해서 원하는 애니메이션 효과를 만들 수 있습니다. 브라우저는 CSS 셀렉터로 지정할 수 있는 별도의 전환 엘리먼트를 생성합니다.
커스텀 전환을 만들려면 다음 단계를 진행하세요.
- view-transition-name 추가 — 애니메이션을 적용할 엘리먼트에 고유한 이름을 지정합니다.
- 전역 애니메이션 정의 — 전역 스타일에 CSS 애니메이션을 작성합니다.
- 전환 가상 엘리먼트 지정 —
::view-transition-old(),::view-transition-new()셀렉터를 사용합니다.
다음 예제는 카운터 엘리먼트에 회전 효과를 추가합니다.
/* 키프레임 애니메이션을 정의합니다. */
@keyframes rotate-out {
to {
transform: rotate(90deg);
}
}
@keyframes rotate-in {
from {
transform: rotate(-90deg);
}
}
/* 뷰 전환 가상 엘리먼트를 지정합니다. */
::view-transition-old(count),
::view-transition-new(count) {
animation-duration: 200ms;
animation-name: -ua-view-transition-fade-in, rotate-in;
}
::view-transition-old(count) {
animation-name: -ua-view-transition-fade-out, rotate-out;
}
중요: 뷰 전환 애니메이션은 컴포넌트 스타일이 아닌 전역 스타일 파일에 정의하세요. Angular의 뷰 캡슐화는 컴포넌트 스타일의 범위를 제한하기 때문에 전환 가상 엘리먼트를 올바르게 지정할 수 없습니다.
StackBlitz에서 수정된 "count" 예제 실행하기
onViewTransitionCreated로 전환 동작 세밀하게 제어하기
withViewTransitions 기능은 뷰 전환을 세밀하게 제어할 수 있도록 onViewTransitionCreated 콜백이 있는 옵션 객체를 받습니다.
이 콜백은 다음과 같이 동작합니다.
- 의존성 주입 컨텍스트에서 실행됩니다.
- 다음 정보가 있는
ViewTransitionInfo객체를 받습니다.startViewTransition의ViewTransition인스턴스- 떠나는 라우팅 규칙의
ActivatedRouteSnapshot - 이동할 라우팅 규칙의
ActivatedRouteSnapshot
이 콜백으로 내비게이션 컨텍스트에 맞게 전환 동작을 조정할 수 있습니다. 예를 들어 특정 종류의 내비게이션에서는 전환을 건너뛸 수 있습니다.
import {inject} from '@angular/core';
import {Router, withViewTransitions, isActive, IsActiveMatchOptions} from '@angular/router';
withViewTransitions({
onViewTransitionCreated: ({transition}) => {
const router = inject(Router);
const targetUrl = router.currentNavigation()!.finalUrl!;
// 프래그먼트나 쿼리 파라미터만 바뀌면 전환을 건너뜁니다.
const config: Partial<IsActiveMatchOptions> = {
paths: 'exact',
matrixParams: 'exact',
fragment: 'ignored',
queryParams: 'ignored',
};
const isTargetRouteCurrent = isActive(targetUrl, router, config);
if (isTargetRouteCurrent()) {
transition.skipTransition();
}
},
});
이 예제에서는 같은 페이지 안의 앵커 링크처럼 URL 프래그먼트나 쿼리 파라미터만 바뀌면 뷰 전환을 건너뜁니다.
skipTransition() 메서드는 애니메이션을 생략하면서 내비게이션은 완료할 수 있도록 합니다.
사용자의 모션 환경설정 존중하기
라우터는 사용자의 prefers-reduced-motion 설정과 관계없이 뷰 전환을 실행합니다.
모션을 줄이는 설정이 모든 움직임을 없애려는 뜻은 아니므로, 프레임워크는 이 선택을 애플리케이션에 맡깁니다.
이런 사용자를 위해 움직임이 더 적은 애니메이션을 제공하거나, onViewTransitionCreated 콜백으로 전환을 완전히 건너뛸 수 있습니다:
withViewTransitions({
onViewTransitionCreated: ({transition}) => {
if (matchMedia('(prefers-reduced-motion: reduce)').matches) {
transition.skipTransition();
}
},
});
Chrome 설명 문서의 예제를 Angular에 적용하기
다음 예제는 Chrome 팀 문서의 여러 뷰 전환 기법을 Angular 라우터에서 사용하도록 바꾼 것입니다.
전환 대상이 같은 DOM 엘리먼트일 필요는 없습니다
서로 다른 DOM 엘리먼트도 view-transition-name이 같으면 부드럽게 전환할 수 있습니다.
커스텀 진입 및 퇴장 애니메이션
라우팅 규칙 전환 중 뷰포트에 들어오고 나가는 엘리먼트에 원하는 애니메이션을 만들 수 있습니다.
비동기 DOM 갱신과 콘텐츠 대기
Angular 라우터는 추가 콘텐츠가 로드되기를 기다리는 것보다 즉시 전환하는 것을 우선합니다.
참고: Angular 라우터는 뷰 전환을 지연하는 방법을 제공하지 않습니다. 추가 콘텐츠를 기다리는 동안 페이지와 상호작용할 수 없게 되는 상황을 방지하기 위한 설계입니다. Chrome 문서에서도 "이 시간에는 페이지가 멈추므로 지연을 최소화해야 합니다. … 경우에 따라서는 기다리지 않고 이미 확보한 콘텐츠를 사용하는 편이 낫습니다."라고 설명합니다.
뷰 전환 타입으로 여러 전환 스타일 처리하기
뷰 전환 타입을 사용하면 내비게이션 컨텍스트에 따라 다른 애니메이션 스타일을 적용할 수 있습니다.
뷰 전환 루트의 클래스 이름으로 여러 전환 스타일 처리하기(사용 중단 권고)
이 방식은 전환 루트 엘리먼트의 CSS 클래스로 애니메이션 스타일을 제어합니다.
다른 애니메이션을 멈추지 않고 전환하기
뷰 전환 중에도 다른 페이지 애니메이션을 유지하면 더 역동적인 사용자 경험을 만들 수 있습니다.
JavaScript로 애니메이션 처리하기
복잡한 애니메이션이 필요하면 JavaScript API를 사용해서 뷰 전환을 코드로 제어할 수 있습니다.