CSS 뷰 트랜지션 모듈 레벨 2

W3C 워킹 드래프트,

이 문서에 대한 추가 정보
이 버전:
https://www.w3.org/TR/2024/WD-css-view-transitions-2-20241113/
최신 공개 버전:
https://www.w3.org/TR/css-view-transitions-2/
에디터스 드래프트:
https://drafts.csswg.org/css-view-transitions-2/
히스토리:
https://www.w3.org/standards/history/css-view-transitions-2
피드백:
CSSWG 이슈 저장소
명세 내 인라인
에디터:
Noam Rosenthal (Google)
Khushal Sagar (Google)
Vladimir Levin (Google)
Tab Atkins-Bittner (Google)
이 명세에 대한 수정 제안:
GitHub 에디터

개요

이 모듈은 뷰 트랜지션 API가 문서 간 내비게이션과 어떻게 동작하는지 정의합니다.

CSS는 구조화된 문서(HTML 및 XML 등)의 렌더링을 화면, 인쇄물 등에서 기술하는 언어입니다.

이 문서의 상태

이 섹션은 문서가 공개된 시점의 상태를 설명합니다. 현재 W3C 발행물 목록과 이 기술 보고서의 최신 개정본은 W3C 기술 보고서 인덱스 https://www.w3.org/TR/에서 확인할 수 있습니다.

이 문서는 CSS 워킹 그룹에 의해 워킹 드래프트로, 권고안 트랙을 따라 공개되었습니다. 워킹 드래프트로서의 공개는 W3C 및 그 회원의 승인이나 지지임을 의미하지 않습니다.

이 문서는 초안 문서이며 언제든지 다른 문서에 의해 업데이트, 대체 또는 폐기될 수 있습니다. 진행 중인 작업 외의 용도로 이 문서를 인용하는 것은 적합하지 않습니다.

피드백은 GitHub 이슈 등록(권장)으로 보내주세요. 제목에 명세 코드 "css-view-transitions"을 포함해 다음과 같이: “[css-view-transitions] …코멘트 요약…”. 모든 이슈 및 코멘트는 아카이브됩니다. 또는, 피드백은 (아카이브됨) 공개 메일링 리스트 www-style@w3.org로 보낼 수 있습니다.

이 문서는 2023년 11월 3일 W3C 프로세스 문서에 따라 관리됩니다.

이 문서는 W3C 특허 정책에 따라 운영되는 그룹에서 작성되었습니다. W3C는 그룹 산출물과 관련하여 이루어진 공개 특허 공개 목록을 유지합니다; 해당 페이지에는 특허 공개 방법에 대한 안내도 포함되어 있습니다. 개인이 필수 청구(Claim)가 포함된 특허를 실제로 알고 있다고 판단할 경우, W3C 특허 정책 6절에 따라 정보를 공개해야 합니다.

1. 소개

이 섹션은 규범적이지 않습니다.

[css-view-transitions-1]에서 명세된 뷰 트랜지션은 개발자가 document의 시각적 상태 간에 애니메이션 트랜지션을 만들 수 있도록 하는 기능입니다.

레벨 2는 해당 명세를 확장하여, 동일 출처 문서 간 내비게이션에서도 트랜지션을 가능하게 하는 API와 라이프사이클을 추가하며, 더 풍부한 뷰 트랜지션을 쉽게 작성할 수 있도록 몇 가지 기능을 추가합니다.

레벨 2에서는 다음을 정의합니다:

2. 문서 간 뷰 트랜지션

2.1. 개요

이 섹션은 규범적이지 않습니다.

2.1.1. 활성화

동일 문서 뷰 트랜지션에서는 저자가 JavaScript로 startViewTransition을 호출하여 뷰 트랜지션을 시작합니다. 문서 간 뷰 트랜지션에서는 뷰 트랜지션을 트리거하는 것이 두 문서 간의 내비게이션이며, 다음 조건들이 모두 충족되어야 합니다:

자세한 내용은 라이프사이클 섹션을 참고하세요.

2.1.2. 새로운 상태가 안정화될 때까지 대기

동일 문서 뷰 트랜지션에서는 저자가 startViewTransition에 전달된 콜백을 사용하여 트랜지션의 새로운 상태가 안정적일 때를 지정할 수 있습니다. 문서 간 뷰 트랜지션은 선언적이므로, 명시적인 promise는 없습니다. 대신, 사용자 에이전트는 렌더 차단 메커니즘을 활용해 문서가 안정화되었는지 판단합니다. 저자는 blocking 속성을 사용하여 트랜지션을 다음 조건까지 지연시킬 수 있습니다:

참고: 렌더 차단 메커니즘을 과도하게 사용하면 이전 상태가 오랫동안 정지되어 사용자 경험이 저하될 수 있습니다. 이를 방지하기 위해 렌더 차단 요소가 적시에 제공되도록 하는 것이 좋습니다.

이 예시에서는 아래 조건이 모두 충족될 때까지 이전 문서의 마지막 프레임이 표시되고, 애니메이션이 지연됩니다:

<!DOCTYPE html>
<html>
	<head>
		< !-- 이것은 기본적으로 렌더 차단됩니다 -->
		<link rel="stylesheet" href="style.css">

		< !-- 이 스크립트가 레이아웃을 보정하므로, 렌더 차단으로 지정하면
			  뷰 트랜지션이 활성화되기 전에 실행을 보장할 수 있습니다 -->
		<script async href="fixup.js" blocking="render"></script>

		< !-- main-article 요소가 확인되고 완전히 파싱될 때까지
			  트랜지션 활성화를 대기 -->
		<link rel="expect" href="#main-article" blocking="render">
	</head>
	<body>
		<header>...</header>
		<main>
			<article id="main-article">...</article>
		</main>
		<article id="secondary-article">...</article>
	</body>
</html>

2.1.3. 사용자 정의

ViewTransition 객체는 스크립트에서 트랜지션을 사용자 정의할 수 있게 해줍니다. 동일 문서 뷰 트랜지션에서는 ViewTransition 객체 하나가 startViewTransition 호출을 통해 전체 라이프사이클에 사용됩니다. 문서 간 뷰 트랜지션에서는 이전 문서와 새 문서 각각에 ViewTransition 객체가 하나씩 생성됩니다.
2.1.3.1. 이전 문서에서 뷰 트랜지션 처리

pageswap 이벤트는 문서가 다른 문서로 교체되기 직전에 마지막으로 발생합니다. 이 이벤트를 통해 뷰 트랜지션이 발생하려는지 확인할 수 있고, types를 사용해 트랜지션을 사용자 정의하거나, 캡처된 요소를 마지막 순간에 변경하거나, 필요하다면 트랜지션을 건너뛸 수 있습니다. PageSwapEvent 인터페이스는 viewTransition 객체를 갖고 있으며, 내비게이션이 뷰 트랜지션에 적합한 경우 null이 아닙니다. 그리고 activation 객체를 통해 리다이렉트 이후의 URL 등 내비게이션 정보를 제공합니다. 트랜지션의 finished promise는 나중에 문서가 BFCache에서 복원될 때 정리 작업에 사용할 수 있습니다.

2.1.3.2. 새 문서에서 뷰 트랜지션 처리

pagereveal 이벤트는 새 문서의 첫 번째 프레임이 표시되기 직전에 발생합니다. 이 이벤트를 통해 viewTransition 속성을 조회하여 뷰 트랜지션이 여전히 유효한지 확인할 수 있습니다. 동일 문서 뷰 트랜지션과 마찬가지로, 저자는 types를 선택하거나, 캡처된 요소를 마지막 순간에 변경하거나, ready 상태를 기다려 애니메이션을 실행하거나, 트랜지션을 건너뛸 수 있습니다.

2.1.4. 라이프사이클

이 섹션은 규범적이지 않습니다.

성공적인 문서 간 뷰 트랜지션은 다음과 같은 단계로 진행됩니다:

  1. 이전 Document에서:

    1. 사용자가 링크를 클릭하거나 폼을 제출하거나 브라우저의 뒤로가기 버튼을 누르는 등 내비게이션을 시작합니다.

      참고: 일부 내비게이션은 뷰 트랜지션을 트리거하지 않습니다. 예를 들어, URL 바에 새 주소를 입력하는 경우 등입니다.

    2. Document 가 활성화될 준비가 되면 pageswap 이벤트가 발생합니다.

    3. 내비게이션이 동일 출처이고, 교차 출처 리다이렉트가 없으며, 이전 Document문서 간 뷰 트랜지션에 옵트인한 경우, 이벤트의 viewTransition 속성은 ViewTransition 객체가 됩니다.

    4. 저자는 이제 types를 변경하거나, skip 으로 트랜지션을 건너뛰는 등 트랜지션을 사용자 정의할 수 있습니다.

    5. ViewTransition 이 건너뛰어지지 않은 경우, 이전 문서의 상태가 캡처됩니다.

    6. 내비게이션이 진행됩니다: 이전 Document 는 언로드되고, 새 Document 가 활성화됩니다.

  2. 그 다음, 새 Document에서:

    1. Document 가 첫 렌더링 기회를 가질 준비가 되면, 새 pagereveal 이벤트가 새 Document 에 발생하며, viewTransition 속성이 포함됩니다.

    2. ViewTransitionupdateCallbackDone promise는 이미 resolve되어 있으며, 캡처된 요소들은 이전 Document에서 전달됩니다.

    3. 여기서도 저자는 types를 변경하거나, skip 으로 트랜지션을 건너뛰는 등 사용자 정의를 할 수 있습니다.

    4. 새 문서의 상태가 캡처되어 트랜지션의 "새" 상태가 됩니다.

    5. 이 시점부터 트랜지션은 동일 문서 트랜지션과 유사하게 activate view transition 단계로 이어집니다.

2.2. 예시

첫 번째 예시 CSS View Transitions 1 § 1.6 예시와 동일한 크로스-페이드 효과를 문서 간에도 생성하려면 JavaScript가 필요하지 않습니다.

대신, 페이지 1과 페이지 2 모두에서 내비게이션 시 뷰 트랜지션 트리거에 옵트인합니다:

// 두 문서 모두에서:
@view-transition {
	navigation: auto;
}

페이지 1에서 페이지 2로 또는 그 반대 링크를 클릭하면 예시 1의 크로스페이드 트랜지션이 생성됩니다. 예시 2, 3, 4의 효과를 내고 싶다면, 의사 요소용 CSS를 두 문서 모두에 추가하세요.

@view-transition 규칙은 미디어 쿼리와 함께 사용할 수 있습니다. 예를 들어, 아래와 같이 하면 화면 너비가 다음보다 클 때만 트랜지션이 실행됩니다:
@view-transition {
	navigation: auto;
}

@media (max-width: 600px) {
	navigation: none;
}
예시 5와 같은 효과를 내려면 다음과 같은 작업을 수행해야 합니다:

두 페이지 모두에서:

@view-transition {
	navigation: auto;
}
이전 페이지에서:
addEventListener('click', event => {
	sessionStorage.setItem("lastClickX", event.clientX);
	sessionStorage.setItem("lastClickY", event.clientY);
});
새 페이지에서:
// 이 코드는 초기 로드와 BFCache 복원 시 모두 실행됩니다.
addEventListener("pagereveal", async event => {
	if (!event.viewTransition)
		return;

	const x = sessionStorage.getItem("lastClickX") ?? innerWidth / 2;
	const y = sessionStorage.getItem("lastClickY") ?? innerHeight / 2;

	const endRadius = Math.hypot(
		Math.max(x, innerWidth - x),
		Math.max(y, innerHeight - y)
	);

	await event.viewTransition.ready;

	// 새 문서의 뷰에 애니메이션 적용
	document.documentElement.animate(
		{
			clipPath: [
				<code data-opaque bs-autolink-syntax='`circle(0 at ${x}px ${y}px)`'>circle(0 at ${x}px ${y}px)</code>,
				<code data-opaque bs-autolink-syntax='`circle(${endRadius}px at ${x}px ${y}px)`'>circle(${endRadius}px at ${x}px ${y}px)</code>,
			],
		},
		{
			duration: 500,
			easing: 'ease-in',
			pseudoElement: '::view-transition-new(root)'
		}
	);
})
내비게이션 속성이나 특정 이미지 로딩 여부에 따라 캡처할 요소를 선택하려면:

이전 페이지에서:

window.addEventListener("pageswap", event => {
	// 예를 들어, 페이지가 숨겨졌거나 내비게이션이 문서 간인 경우 등
	if (!event.viewTransition)
		return;

	// 뒤로/앞으로 내비게이션에 뷰 트랜지션을 적용하지 않으려면...
	if (event.activation.navigationType === "traverse") {
		event.viewTransition.skipTransition();
	}

	const newURL = new URL(event.activation.entry.url);
	if (newURL.pathname === "/details" && thumbnail.complete) {
		thumbnail.classList.add("transition-to-hero");

		// 페이지가 BFCache에서 복원될 때 상태를 정리합니다.
		event.viewTransition.finished.then(() => {
			thumbnail.classList.remove("transition-to-hero");
		});
	}

});

새 페이지에서:

window.addEventListener("pagereveal", event => {
	// 예를 들어, 페이지가 숨겨졌거나, 문서 간 내비게이션이거나, 이전 문서에서 트랜지션이 건너뛰어진 경우 등
	if (!event.viewTransition)
		return;

	const oldURL = new URL(navigation.activation.from.url);
	if (newURL.pathname === "/list") {
		event.viewTransition.types.add("coming-from-list");

		// 뷰 트랜지션이 끝날 때까지 썸네일을 표시합니다.
		if (!hero.complete) {
			setToThumbnail(hero);
			event.viewTransition.finished.then(() => {
				setToFullResolution(hero);
			})
		}
	}
});

2.3. 문서 간 뷰 트랜지션 옵트인

2.3.1. @view-transition 규칙

@view-transition 규칙은 문서가 문서 간 내비게이션 시 ViewTransition을 설정하고 활성화하도록 지정하는 데 사용됩니다.

@view-transition 규칙의 문법은 다음과 같습니다:

@view-transition {
  <declaration-list>
}

@view-transition 규칙은 navigationtypes 디스크립터를 허용합니다.

참고: 기본 동작에 따라 @view-transition 규칙은 조건부 그룹 규칙 (@media 또는 @supports 등) 안에 중첩될 수 있습니다.

@view-transition 규칙이 Document document에 대해 변경될 때, 사용자 에이전트는 outbound 트랜지션에 대한 옵트인 상태를 업데이트해야 합니다.

참고: 내비게이션 시 병렬로 읽어야 하므로, 이 결과를 boolean으로 캐싱해야 합니다.

2.3.2. navigation 디스크립터

이름: navigation
적용 대상: @view-transition
값: auto | none
초기값: none

'navigation' 디스크립터는 특정 타입의 내비게이션을 수행할 때 자동으로 뷰 트랜지션을 시작하도록 옵트인합니다. 이전 문서와 새 문서 모두에 존재해야 합니다.

none

트랜지션이 발생하지 않습니다.

auto

트랜지션은 내비게이션이 동일 출처이고 교차 출처 리다이렉트가 없으며, NavigationType이 아래와 같을 때 활성화됩니다:

참고: auto에서 제외되는 내비게이션은 URL 주소창을 통한 이동, 북마크 클릭, 사용자 또는 스크립트가 reload를 실행하는 경우 등입니다.

이 at-rule은 CSS의 forward-compatible 파싱 요구사항을 준수합니다. 해당 규칙을 이해하지 못하는 적합한 파서도 오류 없이 무시합니다. 인식되지 않거나 구현되지 않은 디스크립터, 또는 이 명세나 향후 버전에서 정의된 문법과 일치하지 않는 값은 전체적으로 무시되어야 하며, @view-transition 규칙을 무효화하지 않습니다.

2.3.3. CSSOM을 사용한 @view-transition 규칙 접근

CSSViewTransitionRule@view-transition 규칙을 나타냅니다.

[Exposed=Window]
interface CSSViewTransitionRule : CSSRule {
  readonly attribute CSSOMString navigation;
  [SameObject] readonly attribute FrozenArray<CSSOMString> types;
};

navigation getter 단계는 해당 navigation 디스크립터가 존재하면 그 값을, 그렇지 않으면 빈 문자열을 반환합니다.

types getter 단계는 해당 types 디스크립터가 존재하면 그 값을, 그렇지 않으면 빈 list를 반환합니다.

3. 선택적 뷰 트랜지션

3.1. 개요

이 섹션은 규범적이지 않습니다.

단순한 페이지에서 하나의 뷰 트랜지션만 있을 경우, 참여하는 요소에 view-transition-name 속성을 설정하는 것만으로 충분합니다. 하지만 더 복잡한 상황에서는 여러 뷰 트랜지션을 선언하고, 동시에 한 개만 실행하고 싶을 수 있습니다. 예를 들어, 내비게이션 바 클릭 시 페이지 전체를 슬라이드하거나, 리스트 항목을 드래그할 때 리스트를 정렬하는 경우 등입니다.

각 뷰 트랜지션마다 필요한 것만 캡처되고, 서로 영향을 주지 않도록 하기 위해 이 명세에서는 active types 개념과, :active-view-transition:active-view-transition-type() 의사 클래스를 도입합니다.

:active-view-transitiondocument elementactive view transition이 있을 때 매칭되고, :active-view-transition-type()는 선택자에 지정된 타입이 document elementactive view transitionactive types와 일치할 때 매칭됩니다.

ViewTransitionactive types는 다음 중 하나의 방식으로 지정됩니다:

  1. startViewTransition(callbackOptions) 호출 시 인자로 전달

  2. 트랜지션의 types를 언제든 변경

  3. 문서 간 뷰 트랜지션에서는 types 디스크립터로 선언

3.2. 예시

예를 들어, 개발자가 다음과 같이 트랜지션을 시작할 수 있습니다:
document.startViewTransition({update: updateTheDOMSomehow, types: ["slide-in", "reverse"]});

이렇게 하면 다음과 같은 선택자가 모두 활성화됩니다:

:root:active-view-transition-type(slide-in) {}
:root:active-view-transition-type(reverse) {}
:root:active-view-transition-type(slide-in, reverse) {}
:root:active-view-transition-type(slide-in, something-else) {}
:root:active-view-transition {}

타입 없이 트랜지션을 시작하면 ':active-view-transition'만 활성화됩니다:

document.startViewTransition(updateTheDOMSomehow);
// 또는
document.startViewTransition({update: updateTheDOMSomehow});
/* 활성화됨 */
:root { }
:root:active-view-transition {}

/* 활성화되지 않음 */
:root:active-view-transition-type(slide-in) {}
:root:active-view-transition-type(any-type-at-all-except-star) {}

3.3. 활성 뷰 트랜지션 기반 선택

3.3.1. :active-view-transition 의사 클래스

:active-view-transition 의사 클래스는 문서의 루트 요소에 적용되며, 해당 요소가 active view transition을 가지고 있을 때 활성화됩니다.

특이성(specificity):active-view-transition의 경우 의사 클래스 셀렉터 하나입니다.

:active-view-transition 의사 클래스는 document elementnode documentactive view transition이 non-null일 때 매칭됩니다.

3.3.2. :active-view-transition-type() 의사 클래스

:active-view-transition-type() 의사 클래스는 문서의 루트 요소에 적용되며, 해당 요소에 매칭되는 active view transition이 있을 때 활성화됩니다. 문법 정의는 다음과 같습니다:

:active-view-transition-type(<custom-ident>#)

특이성:active-view-transition-type()의 경우 의사 클래스 셀렉터 하나입니다.

:active-view-transition-type() 의사 클래스는 document elementnode document 에 non-null active view transition이 있고, 그 active types선택자 인자 중 하나 이상이 포함되어 있을 때 매칭됩니다.

3.4. 진행 중인 뷰 트랜지션의 타입 변경

ViewTransition 인터페이스는 아래처럼 확장됩니다:

[Exposed=Window]
interface ViewTransitionTypeSet {
  setlike<DOMString>;
};

[Exposed=Window]
partial interface ViewTransition {
  attribute ViewTransitionTypeSet types;
};

ViewTransitionTypeSet 객체는 특별한 의미 없이 문자열의 집합(set)을 나타냅니다.

참고: ViewTransitionTypeSet 에는 :active-view-transition-type에 유효하지 않은 문자열, 예를 들어 <custom-ident>가 아닌 문자열도 포함될 수 있습니다.

types getter stepsthisactive types를 반환합니다.

3.5. 문서 간 뷰 트랜지션의 타입 활성화

types 디스크립터

이름: types
적용 대상: @view-transition
값: none | <custom-ident>+
초기값: none

'types' 디스크립터는 트랜지션을 캡처하거나 수행할 때 active types를 설정합니다. 이는 startViewTransition(callbackOptions)를 해당 types로 호출하는 것과 같습니다.

참고: types 디스크립터는 정의된 Document에만 적용됩니다. 저자가 선택한 타입 집합을 두 문서 모두에서 사용해야 합니다.

4. 뷰 트랜지션 의사 요소 간 스타일 공유

4.1. 개요

이 섹션은 규범적이지 않습니다.

DOM에서 여러 요소를 비슷하게 스타일링할 때, class 속성을 사용하는 것이 일반적입니다. 여러 요소에 공통 이름을 지정하고 클래스 셀렉터로 공유 스타일을 선언합니다.

뷰 트랜지션 의사 요소(예: view-transition-group())는 DOM에 정의되어 있지 않고, view-transition-name 속성으로 정의됩니다. 이를 위해 view-transition-class CSS 속성이 뷰 트랜지션에 HTML 클래스와 동등한 기능을 제공합니다. view-transition-nameview-transition-class 값이 함께 있는 요소는 의사 요소에서 선택할 수 있으며, 예시처럼 사용할 수 있습니다.

4.2. 예시

이 예시에서는 각각의 박스가 고유 이름으로 트랜지션에 참여하면서, 모든 박스의 애니메이션에 1초의 지속시간을 적용합니다:
<div class="box" id="red-box"></div>
<div class="box" id="green-box"></div>
<div class="box" id="yellow-box"></div>
div.box {
	view-transition-class: any-box;
	width: 100px;
	height: 100px;
}
#red-box {
	view-transition-name: red-box;
	background: red;
}
#green-box {
	view-transition-name: green-box;
	background: green;
}
#yellow-box {
	view-transition-name: yellow-box;
	background: yellow;
}

/* 아래 스타일은 'view-transition-class' 덕분에 모든 박스에 적용됩니다 */
::view-transition-group(*.any-box) {
	animation-duration: 1s;
}

4.3. view-transition-class 속성

이름: view-transition-class
값: none | <custom-ident>+
초기값: none
적용 대상: 모든 요소
상속: 아니오
퍼센트값: 해당 없음
계산값: 명시된 값 그대로
표준 순서: 문법에 따라
애니메이션 타입: 불연속(discrete)

view-transition-class는 서로 다른 명명된 뷰 트랜지션 의사 요소에 동일한 스타일 규칙을 적용하는 데 사용할 수 있습니다. view-transition-name은 이전 상태의 요소와 새 상태의 대응 요소를 연결하는 데 사용되고, view-transition-class는 뷰 트랜지션 의사 요소 (::view-transition-group(), ::view-transition-image-pair(), ::view-transition-old(), ::view-transition-new())에서 스타일을 적용하는 용도로만 사용됩니다.

참고로 view-transition-class만으로는 요소가 캡처 대상으로 표시되지 않으며, view-transition-name이 이미 지정된 요소에 추가적인 스타일링 방법으로만 사용됩니다.

none

이 요소에 대해 생성된 명명된 뷰 트랜지션 의사 요소에는 클래스가 적용되지 않습니다.

<custom-ident>+

지정된 모든 <custom-ident> 값(단, none 제외)은 명명된 뷰 트랜지션 의사 요소 셀렉터에서 사용할 때 모두 적용됩니다. noneview-transition-class<custom-ident>으로는 유효하지 않으며, 다른 <custom-ident>와 함께 사용해도 마찬가지입니다.

각 '뷰 트랜지션 클래스'는 트리 범위 이름(tree-scoped name)입니다.

참고: 동일 view-transition-name이 트랜지션의 이전/새 상태 모두에 지정된 경우, 새 상태의 view-transition-class 값만 적용됩니다. 문서 간 뷰 트랜지션에도 동일하게 적용되며, 이전 문서의 클래스는 새 문서에 해당 view-transition-name이 없을 때만 적용됩니다.

4.4. 명명된 뷰 트랜지션 의사 요소에 대한 추가 사항

명명된 뷰 트랜지션 의사 요소 (view-transition-group(), view-transition-image-pair(), view-transition-old(), view-transition-new()) 는 다음 구문을 지원하도록 확장됩니다:

::view-transition-group(<pt-name-and-class-selector>)
::view-transition-image-pair(<pt-name-and-class-selector>)
::view-transition-old(<pt-name-and-class-selector>)
::view-transition-new(<pt-name-and-class-selector>)

여기서 <pt-name-selector>는 기존 정의대로 동작하며, <pt-name-and-class-selector>는 다음 구문 정의를 가집니다:

<pt-name-and-class-selector> = <pt-name-selector> <pt-class-selector>? | <pt-class-selector>
<pt-class-selector> = ['.' <custom-ident>]+

위 문법을 해석할 때, 공백은 허용되지 않습니다:

명명된 뷰 트랜지션 의사 요소 selector에 하나 이상의 <custom-ident> 값이 <pt-class-selector>에 포함되어 있으면, 해당 class list 값이 named elements의 해당 의사 요소 view-transition-name 값 전체를 포함할 때만 요소에 매칭됩니다.

다음의 경우 명명된 뷰 트랜지션 의사 요소 특이성타입 셀렉터(type selector)와 동일합니다:

특이성명명된 뷰 트랜지션 의사 요소 selector에서 * 인자가 사용되고 <pt-class-selector>가 비어 있으면 0입니다.

5. document.startViewTransition() 확장

dictionary StartViewTransitionOptions {
  ViewTransitionUpdateCallback? update = null;
  sequence<DOMString>? types = null;
};

partial interface Document {
  ViewTransition startViewTransition(optional (ViewTransitionUpdateCallback or StartViewTransitionOptions) callbackOptions = {});
};
method steps for startViewTransition(callbackOptions)는 아래와 같습니다:
  1. updateCallback을 null로 둡니다.

  2. callbackOptionsViewTransitionUpdateCallback인 경우, updateCallbackcallbackOptions로 설정합니다.

  3. 그 외에 callbackOptionsStartViewTransitionOptions인 경우, updateCallbackcallbackOptionsupdate로 설정합니다.

  4. thisactive view transition이 null이 아니고, 그 outbound post-capture steps가 null이 아니라면,

    1. preSkippedTransitionthisrelevant realm에서 ViewTransitionupdate callbackupdateCallback을 가진 새 객체로 둔다.

      참고: preSkippedTransitiontypes 값은 트랜지션이 활성화되지 않으므로 무시됩니다.

    2. Skip preSkippedTransition with "InvalidStateError" DOMException으로 처리합니다.

    3. preSkippedTransition을 반환합니다.

    참고: 이는 pageswap 발생 후 시작된 동일 문서 트랜지션이 건너뛰어지도록 보장합니다.

  5. viewTransitionmethod stepsstartViewTransition(updateCallback)updateCallback을 전달하여 실행한 결과로 둡니다.

  6. callbackOptionsStartViewTransitionOptions인 경우, viewTransitionactive typestypesclone으로 set으로 설정합니다.

  7. viewTransition을 반환합니다.

6. view-transition-name 자동 결정

6.1. 개요

이 섹션은 규범적이지 않습니다.

요소가 뷰 트랜지션에 참여하려면 고유한 view-transition-name을 받아야 합니다. 여러 요소가 동일 뷰 트랜지션에 관여하는 경우, 특히 많은 요소가 same-element 트랜지션(즉, 이전과 새 상태에서 view-transition-name이 동일)일 때, 이 작업은 번거롭고 장황할 수 있습니다.

이를 쉽게 하기 위해, view-transition-nameauto로 설정하면, 요소에 대해 view-transition-name이 생성되거나, 해당 요소에 id가 있으면 그 값을 사용합니다.

6.2. 예시

이 예시에서는 뷰 트랜지션을 사용해 리스트를 애니메이션으로 정렬합니다:
<ul>
	<li>Item 1</li>
	<li>Item 2</li>
	<li>Item 3</li>
	<li>Item 4</li>
	...
</ul>

일반적으로 각 항목마다 고유한 view-transition-name을 지정해야 합니다:

li:nth-child(1) { view-transition-name: item1; }
li:nth-child(2) { view-transition-name: item1; }
li:nth-child(3) { view-transition-name: item1; }
li:nth-child(4) { view-transition-name: item1; }
...

auto를 사용하면 아래 CSS로 동작합니다:

li {
	view-transition-name: auto;
}

6.3. view-transition-name에 대한 추가 사항

기존 값 외에도, view-transition-nameauto 키워드도 허용합니다. element에 대해 view-transition-nameused value를 결정하는 과정은 다음과 같습니다:

  1. computedcomputed value로 둡니다. view-transition-name

  2. computednone이면 null 반환

  3. computed<custom-ident>이면 computed 반환

  4. Assert: computedauto입니다.

  5. elementid가 있고, computedelementroot와 동일 루트에 연결된 경우, elementid 값을 반환

    참고: ::part() 의사 요소는 해당 요소의 id로 해석되지 않습니다.

  6. 고유 문자열을 반환. 이 문자열은 해당 요소와 Document에 대해 일관되고 고유해야 하며, 적어도 elementnode documentactive view transition 동안에는 유지되어야 합니다.

    참고: 이 문자열은 웹에서 관찰되지 않으며, 내부 알고리즘에서 요소를 식별하는 용도로 사용됩니다.

    참고: 문서 간 뷰 트랜지션에서 사용할 경우, 생성된 auto 값은 절대 일치하지 않으므로, 각각의 ::view-transition-group() 의사 요소가 별도로 생성됩니다 (하나는 종료, 하나는 진입).

auto로 생성된 view-transition-name트리 범위 이름(tree-scoped name)입니다.

7. 중첩 뷰 트랜지션

7.1. 개요

이 섹션은 규범적이지 않습니다.

기본적으로 여러 요소에 view-transition-name을 지정하면 평면 뷰 트랜지션 트리가 생성되어, 모든 ::view-transition-group() 의사 요소가 ::view-transition 의사 요소의 자식이 됩니다. 이는 많은 단순한 사용 사례에서는 충분하지만, 평면 트리로는 구현이 어려운 스타일링 사례도 있습니다. 대표적인 사례는 클리핑입니다. 평면 트리에서는 모든 의사 요소가 스냅샷 포함 블록에 클리핑되어, 원래 트리에서 클리핑된 요소가 뷰 트랜지션 중에는 클리핑을 잃어 시각적 효과가 깨질 수 있습니다. 평면 트리에서 예상하지 못한 시각적 효과가 발생할 수 있는 경우:

이러한 사용 사례를 가능하게 하기 위해, 본 명세는 뷰 트랜지션 의사 요소의 중첩 개념을 도입합니다. view-transition-group CSS 속성을 사용하면, 저자가 생성된 ::view-transition-group() 의사 요소의 "부모 그룹"을 지정해 뷰 트랜지션 트리에 계층 구조를 만들 수 있습니다.

7.2. 예시

이 예시에서는 뷰 트랜지션 트리가 평면이 아닌 중첩 구조를 가지도록 트랜지션을 생성합니다:
<section class="container">
	<article>Content</article>
</section>
.container {
	view-transition-name: container;
}

.container,
::view-transition-group(container) {
	clip-path: circle();
}

article {
	view-transition-name: article;
	view-transition-group: container;
}

컨테이너 요소와 해당 의사 요소 모두에 clip-path를 적용하면 트랜지션 중에도 클리핑이 유지되고, 내부 요소에 view-transition-group을 컨테이너로 지정하면 트리가 중첩되어 클리핑이 제대로 적용됩니다.

7.3. view-transition-group 속성

이름: view-transition-group
값: normal | contain | nearest | <custom-ident>
초기값: normal
적용 대상: 모든 요소
상속: 아니오
퍼센트값: 해당 없음
계산값: 명시된 값 그대로
표준 순서: 문법에 따라
애니메이션 타입: 불연속(discrete)

view-transition-group 속성은 view-transition-name과 함께 사용하여 명명된 뷰 트랜지션 의사 요소의 계층 구조를 생성할 수 있습니다.

used valueview-transition-group에 대해 계산될 때, 조상 체인에서 view-transition-name을 찾거나 none으로 결정됩니다. 명명된 뷰 트랜지션 의사 요소를 생성할 때, 해당 이름을 가진 ::view-transition-group()이 이 요소의 ::view-transition-group()의 부모가 됩니다. view-transition-name 기준입니다.

8. 레이어드 캡처

8.1. 개요

이 섹션은 규범적이지 않습니다.

[css-view-transitions-1]에서는 이전 상태와 새 상태가 스냅샷으로 캡처되고, 초기 및 최종 기하 정보가 캡처되어 기본적으로 크로스페이드 애니메이션이 생성됩니다. 이는 단순한 모델이며 대부분의 경우 원하는 결과를 만듭니다.

하지만 두 개의 평면 스냅샷을 크로스페이드하는 것은 항상 가장 표현력이 뛰어난 애니메이션은 아닙니다. CSS는 테두리, 그래디언트 배경, filter, box-shadow 등도 애니메이션할 수 있으며, 원하는 UX에 따라 크로스페이드보다 더 자연스럽고 표현력 있게 느껴질 수 있습니다.

또한 중첩 뷰 트랜지션을 사용할 때 CSS 속성이 스냅샷으로 평면화되면 일부 애니메이션이 "잘못" 보일 수 있습니다. 이는 트리 전체에 영향을 주는 효과(예: opacity, mask, clip-pathfilter, 그리고 overflow를 통한 클리핑 등)가 포함됩니다. 이런 효과들은 단일 요소와 콘텐츠가 아니라 요소 트리 전체에 적용되어야 합니다.

레이어드 캡처를 사용하면 트리 전체에 영향을 주는 CSS 속성과 박스 장식류가 스타일로 캡처되어 그룹의 일부로 애니메이션됩니다.

이런 동작을 CSS 속성으로 옵트인/옵트아웃할 수 있어야 하는가? 이슈 11078 참고.

8.2. 캡처되는 CSS 속성 표 {#layered-captured-css-properties}

아래 레이어드 캡처 속성 목록은 레이어드 캡처에 참여하는 CSS 속성을 정의합니다. 요소의 이전/새 상태가 캡처될 때, 이 속성들은 스타일로 캡처되며, 사용자 에이전트는 스냅샷을 렌더링할 때 해당 속성을 무시해야 합니다:

9. 알고리즘

9.1. 데이터 구조

9.1.1. Document의 추가 사항

Document 에는 다음이 추가된다:
inbound view transition params

view transition params 또는 null. 초기값은 null.

can initiate outbound view transition

불리언(boolean). 초기값은 false.

참고: 이 값은 내비게이션 중 병렬로 읽을 수 있다.

9.1.2. ViewTransition의 추가 사항

ViewTransition 에는 다음이 추가된다:
active types

ViewTransitionTypeSet, 초기값은 빈 값.

outbound post-capture steps

null 또는 steps 집합, 초기값은 null.

9.1.3. 직렬화 가능한 view transition params

view transition params 는 여러 문서 간에 뷰 트랜지션 정보를 직렬화하기 위한 struct이다. 다음과 같은 항목을 가진다:
named elements

키는 문자열이고 값은 captured elementsmap.

initial snapshot containing block size

두 개의 숫자(width와 height)로 구성된 tuple.

9.2. 뷰 트랜지션 페이지 가시성 변경 단계에 대한 추가 사항

다음 단계는 document에 대해 view transition page-visibility change steps의 현재 단계 이후에 큐에 추가된다:
  1. documentinbound view transition params를 null로 설정한다.

참고: 이는 HTML 명세에서 호출된다.

9.2.1. 캡처 요소 확장

captured element struct는 기존 필드 외에 다음 필드를 추가로 포함해야 한다:
class list

문자열로 이루어진 list, 초기값은 빈 값.

containing group name

null 또는 문자열, 초기값은 null.

old layered-capture style

문자열.

transform from snapshot containing block

matrix, 초기값은 identity transform function.

old box properties
new box properties

layered box properties 또는 null, 초기값은 null.

layered box properties는 다음 필드를 포함하는 struct이다:

box sizing

border-box 또는 content-box.

content box
padding box

경계 박스 기준 CSS 픽셀 단위의 사각형(rectangle).

9.3. @view-transition 규칙 해결

@view-transition 규칙 해결Document document에 대해 실행:

참고: 이는 이전 문서와 새 문서 모두에서 호출된다.

  1. documentvisibility state가 "hidden"이면, "skip transition" 반환.

  2. matchingRuledocument의 마지막 @view-transition 규칙으로 둔다.

  3. matchingRule이 없으면 "skip transition" 반환.

  4. matchingRulenavigation 디스크립터의 computed valuenone이면 "skip transition" 반환.

  5. Assert: matchingRulenavigation 디스크립터의 computed valueauto이다.

  6. typesDescriptormatchingRuletypes 디스크립터로 둔다.

  7. typesDescriptorcomputed valuenone이면, 집합(set) « » 반환.

  8. typesDescriptorcomputed value에 해당하는 문자열의 집합(set) 반환.

9.4. 이전 Document에서 뷰 트랜지션 설정

9.4.1. 문서 간 뷰 트랜지션의 가능 여부 확인

내비게이션이 문서 간 뷰 트랜지션을 트리거할 수 있는가?Document oldDocument, Document newDocument, NavigationType navigationType, boolean isBrowserUINavigation을 인자로 받는다:

참고: 이는 내비게이션 중, 병렬로 호출될 수 있다.

  1. 사용자 에이전트가 뒤로가기 내비게이션 등 구현 정의(implementation-defined) 내비게이션 경험(예: 제스처 기반 트랜지션)을 표시하기로 결정한다면, 저자가 정의한 뷰 트랜지션을 무시할 수 있다. 이 경우 false 반환.

  2. oldDocumentcan initiate outbound view transition이 false면 false 반환.

  3. navigationTypereload이면 false 반환.

  4. oldDocumentoriginnewDocumentorigin동일 출처가 아니면 false 반환.

  5. newDocument교차 출처 리다이렉트로 생성되었고, newDocumentlatest entry가 null이면 false 반환.

    참고: Documentlatest entry가 null인 경우는 BFCache에서 복원이 아닌 새 내비게이션일 때 발생한다.

  6. navigationTypetraverse이면 true 반환.

  7. isBrowserUINavigation이 true면 false 반환.

  8. true 반환.

9.4.2. 페이지 교체 준비 시 아웃바운드 트랜지션 설정

문서 간 뷰 트랜지션 설정Document oldDocument, Document newDocument, proceedWithNavigation (인자 없는 알고리즘)으로 호출:

참고: 이는 HTML 명세에서 호출됩니다.

  1. Assert: 이 단계는 oldDocument에 큐된 task의 일부로 실행 중임.

  2. oldDocumentcan initiate outbound view transition이 false이면 null 반환.

  3. transitionTypesFromRuleoldDocument에 대해 @view-transition 규칙 해결의 결과로 둔다.

  4. Assert: transitionTypesFromRule은 "skip transition"이 아님.

    참고: newDocument가 옵트인했는지는 아직 알 수 없음. 파싱이 안 됐을 수도 있음. newDocument의 옵트인은 pagereveal 이벤트 발생 시 확인함.

  5. oldDocumentactive view transition이 null이 아니면, skip oldDocumentactive view transition을 "AbortError" DOMException 으로 oldDocumentrelevant Realm에서 처리함.

    참고: 이는 문서 언로드 준비 시 실행 중인 트랜지션을 모두 건너뛰게 한다는 의미임.

  6. outboundTransitionoldDocumentrelevant Realm에서 새 ViewTransition 객체로 둔다.

  7. outboundTransitionactive typestransitionTypesFromRule로 설정.

    참고: active types는 문서 간 공유되지 않음. 새 문서에서 types 를 조작해도 newDocument에는 영향을 미치지 않으며, newDocument에서는 types 디스크립터 값을 읽음.

    참고: ViewTransition 은 이전 문서가 hidden 상태가 되면 건너뛰어짐.

  8. outboundTransitionoutbound post-capture steps를 아래와 같이 view transition params-or-null params를 인자로 받는 steps로 설정:

    1. newDocumentinbound view transition paramsparams로 설정.

      참고: 인바운드 트랜지션은 pagereveal 디스패치 후 활성화되어, 해당 이벤트 내 변이가 캡처된 새 상태에 적용됨을 보장함.

    2. 타임아웃 후 트랜지션을 건너뛰려면, 사용자 에이전트는 다음 단계를 병렬로 수행할 수 있음:

      1. 구현 정의 duration만큼 대기.

      2. 글로벌 태스크 큐DOM manipulation task source에 올리고, newDocumentrelevant global object에서 아래 단계 수행:

        1. newDocumentinbound view transition paramsparamsnewDocumentinbound view transition params를 null로 설정.

    3. proceedWithNavigation 호출.

  9. oldDocumentactive view transitionoutboundTransition로 설정.

    참고: 이후 과정은 perform pending transition operations에서 이어짐.

  10. 사용자 에이전트는 다음 중 하나가 발생할 때까지 현재 표시된 프레임을 유지해야 함:

    참고: 이전/새 상태 표시 사이에 의도치 않은 플래시가 발생하지 않도록, 트랜지션이 매끄럽게 진행됨을 보장함.

  11. outboundTransition 반환.

9.4.3. 현재 상태를 반영하여 옵트인 플래그 업데이트

outbound 트랜지션에 대한 옵트인 상태 업데이트Document document에 대해 실행:
  1. documenthas been revealed이고, @view-transition 규칙 해결 결과가 "skip transition"이 아니면, documentcan initiate outbound view transition을 true로 설정.

  2. 그 외에는 documentcan initiate outbound view transition을 false로 설정.

9.4.4. 뷰 트랜지션이 건너뛰어진 경우 내비게이션 계속

뷰 트랜지션 건너뛰기 알고리즘에 다음 단계를 추가한다(인자: ViewTransition transition):
  1. transitionoutbound post-capture steps가 null이 아니면, transitionoutbound post-capture steps를 null로 실행.

참고: 이는 monkey-patch 방식으로 작성되었으며, L1 명세가 정식화되면 알고리즘에 통합될 예정.

9.4.5. 이전 상태 캡처 후 문서 간 뷰 트랜지션 진행

perform pending transition operations 알고리즘에 다음 단계를 맨 앞에 추가(Document document):
  1. documentactive view transition이 null이 아니고, 그 outbound post-capture steps가 null이 아니면:

    1. Assert: documentactive view transitionphase가 "pending-capture"임.

    2. viewTransitionParams를 null로 둔다;

    3. document뷰 트랜지션용 렌더링 억제(rendering suppression for view transitions)를 true로 설정.

      이전 상태 캡처가 여기선 동기적 단계처럼 보이지만, 실제로는 요소를 이미지로 렌더링하는 것이 동기적으로 불가능하므로 비동기 단계임. L1 명세에서 더 명확하게 해야 함.

    4. 이전 상태 캡처transition에 대해 수행.

    5. 성공했다면, viewTransitionParams를 새 view transition params로 설정. named elementsclone of transitionnamed elements, initial snapshot containing block sizetransitioninitial snapshot containing block size로.

    6. document뷰 트랜지션용 렌더링 억제를 false로 설정.

    7. transitionoutbound post-capture stepsviewTransitionParams로 호출.

참고: 이는 monkey-patch 방식으로 작성되었으며, L1 명세가 정식화되면 알고리즘에 통합될 예정.

9.5. Document에서 뷰 트랜지션 활성화

문서 간 인바운드 뷰 트랜지션 활성화Document document에 대해 실행:
  1. Assert: documentfully active임.

  2. Assert: documenthas been revealed가 true임.

  3. outbound 트랜지션에 대한 옵트인 상태 업데이트document에 대해 실행.

  4. inboundViewTransitionParamsdocumentinbound view transition params로 둔다.

  5. inboundViewTransitionParams가 null이면 null 반환.

  6. documentinbound view transition params를 null로 설정.

  7. documentactive view transition이 null이 아니면 null 반환.

    참고: 문서가 표시되기 전에 동일 문서 트랜지션이 시작되면, 대기 중인 문서 간 트랜지션이 취소됨을 의미함.

  8. @view-transition 규칙 해결document에 대해 실행하고, 결과를 resolvedRule로 둔다.

  9. resolvedRule이 "skip transition"이면 null 반환.

  10. transitiondocumentrelevant Realm에서 새 ViewTransition 객체로 두고, named elementsinboundViewTransitionParamsnamed elements, initial snapshot containing block sizeinboundViewTransitionParamsinitial snapshot containing block size로 둔다.

  11. documentactive view transitiontransition으로 설정.

  12. Resolve transitionupdate callback done promise를 undefined로 resolve함.

  13. transitionphase를 "update-callback-called"로 설정.

  14. transitionactive typesresolvedRule로 설정.

  15. transition 반환.

9.6. view-transition-class 캡처

요소의 이전 또는 새 상태를 캡처할 때, captured element captureelement element가 주어지면 다음 단계를 수행한다:
  1. captureclass listelementview-transition-classcomputed value로 설정한다. 단, 해당 값이 elementnode document에 연결되어 있을 때만 적용.

참고: 이는 monkey-patch 방식으로 작성되었으며, L1 명세가 정식화되면 알고리즘에 통합될 예정.

9.7. view-transition-group 캡처 및 적용

9.7.1. view-transition-group 값 해결

Element elementdocument-scoped view transition group을 구하려면 다음을 수행:
  1. computedGroup을 element의 view-transition-group 속성의 computed value로 둔다.

  2. computedGroupelementnode document에 연결되어 있으면 computedGroup 반환.

  3. normal 반환.

9.7.2. 컨테이닝 그룹 이름 해결

Element elementnearest containing group name을 구하려면, ViewTransition viewTransition이 주어졌을 때 다음을 수행:

  1. Assert: elementviewTransition에 참여함.

  2. ancestorGroupelementflat tree ancestorviewTransition에 참여하고 document-scoped view transition groupnormal이 아닌 첫 번째 요소로 둔다.

  3. ancestorGroup이 있으면 ancestorGroupdocument-scoped view transition name 반환.

  4. none 반환.

9.7.3. 그룹 이름 해결

Element elementused group name을 구하려면, ViewTransition transition이 주어졌을 때 다음을 수행:
  1. Assert: elementtransition에 참여함.

  2. groupelementdocument-scoped view transition group으로 둔다.

  3. containingGroupNameelementnearest containing group name으로, transition을 인자로 하여 구한다.

  4. group에 따라 첫 번째로 일치하는 조건을 반환:

normal
contain

containingGroupName

참고: contain 값을 가진 요소는 그 하위 요소들에 대해 nearest containing group name이 됨.

nearest

요소의 transition에 참여하는 document-scoped view transition name을 가진 가장 가까운 flat tree ancestor 반환.

<custom-ident>

요소가 flat tree ancestordocument-scoped view transition namegroup이고 transition에 참여하는 요소가 있으면 group 반환. 아니면 containingGroupName 반환.

9.7.4. 기존 view-transition-group 계산

요소의 이전 상태를 캡처할 때, captured element capturedElement, ViewTransition transition, element element가 주어지면:
  1. capturedElementcontaining group nameelementused group name 값으로 설정 (transition 인자).

9.7.5. view-transition-group 계산

요소의 새 상태를 캡처할 때, captured element capturedElement, ViewTransition transition, element element가 주어지면:
  1. capturedElementcontaining group nameelementused group name 값으로 설정 (transition 인자).

9.7.6. ::view-transition-group()을 지정된 컨테이닝 그룹에 재부모화

트랜지션 의사 요소 설정 시, captured element capturedElement, transitionName, transition이 주어지면:
  1. containingGroupNamecapturedElementcontaining group name으로 둔다.

  2. containingGroupName이 null이 아니면:

    1. groupContainerElementtransitionnamed elements[containingGroupName]로 둔다.

    2. group::view-transition-group()으로, view transition nametransitionName으로 설정.

    3. parentGroup::view-transition-group()으로, view transition namecontainingGroupName으로 설정.

    4. parentGroupgroup을 append.

    5. 애니메이션 키프레임 설정 시 transform을 기준으로 중첩 그룹 transform 조정을 수행. groupContainerElementold transform, groupContainerElementold width, groupContainerElementold height, groupContainerElementold box properties를 인자로 사용.

참고: old/new 그룹 불일치 시 처리 방법은 미정. 이슈 10631 참고.

9.7.7. 그룹의 transform 을 컨테이닝 ::view-transition-group() 기준으로 조정

트랜지션 의사 요소 스타일 업데이트 시, captured element capturedElement, transform, ViewTransition transition이 주어지면, 스타일 설정 전 아래 단계를 수행:
  1. capturedElementtransform from snapshot containing blocktransform으로 설정.

  2. capturedElementcontaining group name이 null이 아니면:

    1. groupContainerElementtransitionnamed elements[capturedElementcontaining group name]로 둔다.

    2. containerRectcapturedElementsnapshot containing block이면 해당 값으로, 아니면 capturedElementborder box로 둔다.

    3. 중첩 그룹 transform 조정transform에 수행. groupContainerElementtransform from snapshot containing block, containerRect의 width, containerRect의 height, groupContainerElementnew box properties 인자 사용.

9.8. 레이어드 CSS 속성 캡처

9.8.1. 레이어드 캡처 스타일 계산

Element elementlayered capture style을 계산하려면:
  1. propertiesToCapturelist로, 레이어드 캡처 속성에 해당하는 값으로 초기화.

  2. overflow 및 containment 동작 명세화 필요. 이슈 11079 참고.

  3. styles를 « »로 둔다.

  4. propertiesToCapture의 각 property에 대해, elementcomputed value를 구해서 « property, ":", 값, ";" »로 이어붙인(concatenate) 값을 append한다.

  5. styles이어붙인(concatenate) 값으로 반환.

Element elementlayered capture geometry를 계산하려면, 새 layered box properties를 반환한다. box sizingelementcomputed box-sizing으로, padding boxelementpadding box, content boxelementcontent box로 설정.

element에 대해 default group size를 계산하려면, elementcontent box의 크기를 반환(단, elementcomputed box-sizingcontent-box일 때만). 그 외에는 elementborder box의 크기 반환.

9.8.2. 이전 레이어드 속성 캡처

요소의 이전 상태를 캡처할 때, captured element capturedElementelement element가 주어지면 다음 단계를 수행한다:
  1. capturedElementold layered-capture styleelementlayered capture style로 설정한다.

  2. capturedElementold box propertieselementlayered capture geometry로 설정한다.

  3. capturedElement의 (old width, old height)를 elementdefault group size로 설정한다.

9.8.3. 이미지 캡처 크기 조정

이미지 캡처 시, 이미지의 natural dimensions는 요소의 content box 크기를 기준으로 하며, border box가 기준이 아니다.

9.8.4. 레이어드 캡처로 스냅샷 렌더링

요소를 스냅샷으로 캡처할 때, element contents만 페인팅되고, 요소의 효과와 박스 장식은 페인팅되지 않는다. 구체적으로, 요소의 background, border, border-image, box-shadow, outline은 페인팅되지 않으며, border-radius clip-path filter mask opacity도 적용되지 않는다.

9.8.5. 중첩 그룹 트랜스폼 조정

중첩 그룹 트랜스폼 조정matrix transform, matrix parentTransform, borderBoxWidth, borderBoxHeight, layered box properties boxProperties가 주어지면 다음 단계를 수행한다:
  1. Multiply transformparentTransform의 역행렬을 곱한다.

  2. (left, top)을 boxPropertiespadding box를 (borderBoxWidth, borderBoxHeight) 내에서 기준으로 구한다.

  3. transform을 (-left, -top)만큼 translate한다.

    참고: 이 연산을 통해 기본적으로 중첩된 그룹의 위치가 원래 요소 위치와 동일하게 되며, 기본적으로 중첩 ':view-transition-group'은 부모의 padding edge 기준으로 위치함을 보장한다.

9.8.6. 기존 레이어드 캡처 속성을 ::view-transition-group() 키프레임에 적용

트랜지션 의사 요소 설정 시, captured element capturedElement, transitionName이 주어지면:
  1. keyframesName을 « -ua-view-transition-group-anim-, transitionName » 이어붙인(concatenate) 값으로 둔다.

  2. keyframesName으로 생성한 rule에 capturedElementold layered-capture style을 append한다.

9.8.7. 새 레이어드 캡처 속성을 ::view-transition-group()에 적용

트랜지션 의사 요소 스타일 업데이트 시, transitionName, capturedElement, width, height, Element element가 주어지면:

참고: widthheight는 변경될 수 있음.

  1. styleelementlayered capture style로 둔다.

  2. capturedElementnew box propertieselementlayered capture properties로 설정한다.

  3. (width, height)를 elementdefault group size로 설정한다.

  4. 다음 문자열(변수 치환 포함)을 user-agent 스타일시트에 append한다:

    @keyframes -ua-view-transition-content-geometry-transitionName {
      from {
        width: oldContentWidth;
        height: oldContentHeight;
      }
    }
    
    :root::view-transition-image-pair(transitionName) {
      position: relative;
      inset: unset;
      width: newContentWidth;
      height: newContentHeight;
      animation-name: -ua-view-transition-transitionName;
      animation-direction: inherit;
      animation-timing-function: inherit;
      animation-iteration-count: inherit;
      animation-duration: inherit;
    }
    
  5. (oldContentWidth, oldContentHeight)를, capturedElementold width, capturedElementold height로 설정(단, capturedElementold box properties가 null인 경우), 아니면 capturedElementold box propertiescontent box 크기로 설정.

  6. (newContentWidth, newContentHeight)를 (width, height)로 설정(단, new box properties가 null인 경우), 아니면 capturedElementnew box propertiescontent box 크기로 설정.

  7. 아래 문자열(변수 치환 포함)을 user agent 스타일시트에 append한다:

    @keyframes -ua-view-transition-content-geometry-transitionName {
      from {
        width: oldContentWidth;
        height: oldContentHeight;
      }
    }
    
    :root::view-transition-image-pair(transitionName) {
      position: relative;
      inset: unset;
      width: newContentWidth;
      height: newContentHeight;
      animation-name: -ua-view-transition-transitionName;
      animation-direction: inherit;
      animation-timing-function: inherit;
      animation-iteration-count: inherit;
      animation-duration: inherit;
    }
    

참고: ':view-transition-image-pair' 의사 요소는 relative 포지셔닝을 사용하여, 그룹의 padding 효과가 적용되도록 한다.

프라이버시 고려 사항

이 명세는 새로운 프라이버시 고려 사항을 도입하지 않습니다.

보안 고려 사항

크로스 오리진 문제를 방지하기 위해, 현재 문서 간 뷰 트랜지션은 동일 출처 내비게이션에만 활성화할 수 있습니다. WICG/view-transitions#200에서 논의된 것처럼, 여전히 두 가지 잠재적 위험이 있습니다:

  1. 두 문서의 cross-origin isolated capability가 다를 수 있습니다. 이로 인해 Documentcross-origin isolated인 경우, cross-origin isolated가 아닌 문서의 이미지 데이터를 읽을 수 있는 상황이 발생할 수 있습니다. 이는 이미 [[css-view-transitions-1#sec]]에서 완화되어 있으며, 캡처된 cross-origin iframe에도 동일한 제한이 적용됩니다.

  2. 동일 출처 내비게이션이 교차 출처 리다이렉트를 통해 발생할 수 있습니다. 예를 들어 https://example.com에서 https://auth-provider.com/로 이동 후 https://example.com/loggedin으로 리다이렉트되는 경우입니다.

    이 경우, 교차 출처 측에서 사용자를 예기치 않은 1st-party URL로 리다이렉트하여 예상치 못한 트랜지션이 발생하고, 실제로 리다이렉트가 있었음을 숨길 수 있습니다. 이를 완화하기 위해, 현재 Document교차 출처 리다이렉트로 생성된 경우 내비게이션에서 뷰 트랜지션이 비활성화됩니다. 단, Document재활성화되는 경우에는 이미 리다이렉트가 끝난 상태이므로 이 검사는 적용되지 않습니다.

    참고: 이는 서버 사이드 리다이렉트에만 해당됩니다. 클라이언트 사이드 리다이렉트(예: [^meta/http-equiv/refresh^] 사용)는 새로운 내비게이션과 동등하게 처리됩니다.

  3. 이 기능은 CSS에 더 많은 정보를 노출합니다. 기존까지는 CSS가 내비게이션 관련 정보를 알 수 없었습니다. 따라서 3rd-party CSS의 안전성에 대한 우려가 있을 수 있습니다. 하지만 일반적으로 3rd-party 스타일시트는 신뢰할 수 있는 출처에서 제공되어야 하며, CSS는 문서 정보를 알거나 변경할 수 있는 방법이 많기 때문에 본질적으로 신뢰되어야 합니다.

자세한 논의는 Issue #8684WICG/view-transitions#200를 참고하세요.

부록 A. 변경 사항

이 부록은 비규범적입니다.

2024-05-16 Working Draft 이후 변경 사항 2024-05-16 Working Draft

규격 준수

문서 규약

규격 요구사항은 설명적 단언문과 RFC 2119 용어 조합으로 표현됩니다. “MUST”, “MUST NOT”, “REQUIRED”, “SHALL”, “SHALL NOT”, “SHOULD”, “SHOULD NOT”, “RECOMMENDED”, “MAY”, “OPTIONAL”은 규범적 부분에서 RFC 2119의 정의대로 해석됩니다. 단, 가독성을 위해 본 명세에서는 모두 대문자로 표기하지 않습니다.

이 명세의 모든 내용은 규범적이며, 비규범적으로 표시된 섹션, 예시, 참고만 예외입니다. [RFC2119]

예시는 “for example”라는 말로 시작하거나 class="example"로 구분되어 있습니다. 예시:

이것은 비규범적 예시입니다.

비규범적 참고는 “Note”로 시작하며, class="note"로 구분됩니다. 예:

참고: 이것은 비규범적 참고입니다.

권고(advisement)는 규범적 섹션으로, 특별히 주의가 필요한 부분을 <strong class="advisement">로 구분합니다. 예: UA는 접근 가능한 대안을 반드시 제공해야 한다.

적합성 클래스

이 명세에 대한 규격 준수는 세 가지 클래스에 대해 정의됩니다:

스타일 시트
CSS 스타일 시트.
렌더러
UA (사용자 에이전트): 스타일 시트의 의미를 해석하고 문서를 렌더링함.
작성 도구
UA (작성 도구): 스타일 시트를 작성함.

스타일 시트가 본 명세를 준수하려면, 본 모듈에서 정의한 문법을 사용하는 모든 구문이 CSS 일반 문법 및 각 기능의 개별 문법에 따라 유효해야 합니다.

렌더러가 본 명세를 준수하려면, 해당 스타일 시트를 명세대로 해석하는 것 외에도 본 명세에서 정의한 모든 기능을 올바르게 파싱하고 문서를 올바르게 렌더링해야 합니다. 단, 장치의 한계로 인해 UA가 문서를 올바르게 렌더링하지 못하는 경우라도 비준수로 간주하지 않습니다. (예: 단색 모니터에서 색상을 렌더링할 수 없는 경우)

작성 도구가 본 명세를 준수하려면, 작성하는 스타일 시트가 CSS 일반 문법 및 각 기능의 개별 문법에 맞게 문법적으로 올바르고, 본 명세에서 설명한 모든 스타일 시트 규격 준수 요구사항을 충족해야 합니다.

부분 구현

작성자가 forward-compatible 파싱 규칙을 활용해 폴백 값을 지정할 수 있도록, CSS 렌더러는 사용 가능한 수준의 지원이 없는 at-rule, 속성, 속성 값, 키워드, 기타 구문 구조를 무효로 간주하고 (적절히 무시), 특히 사용자 에이전트는 여러 값이 포함된 속성 선언에서 지원하지 않는 구성 값만 선택적으로 무시하고 지원되는 값만 적용해서는 안 됩니다: 어떤 값이라도 무효(지원하지 않는 값이어야 함)이면 전체 선언을 무시해야 합니다.

불안정 및 독점 기능 구현

향후 안정적인 CSS 기능과의 충돌을 피하기 위해, CSSWG는 최선의 관행에 따라 불안정 기능과 독점 확장을 구현할 것을 권장합니다.

비실험적 구현

명세가 Candidate Recommendation 단계에 도달하면, 비실험적 구현이 가능하며, 구현자는 명세에 따라 올바르게 구현되었음을 입증할 수 있는 CR-level 기능에 대해 접두어 없는 구현을 배포해야 합니다.

CSS의 상호운용성을 확립‧유지하기 위해 CSS Working Group은 비실험적 CSS 렌더러가 구현 보고서(필요시 해당 구현 보고서에 사용된 테스트케이스 포함)를 W3C에 제출해줄 것을 요청합니다. W3C에 제출된 테스트케이스는 CSS Working Group에서 검토‧수정될 수 있습니다.

테스트케이스 및 구현 보고서 제출에 대한 자세한 정보는 CSS Working Group 웹사이트 https://www.w3.org/Style/CSS/Test/에서 확인할 수 있습니다. 문의는 public-css-testsuite@w3.org 메일링 리스트로 보내 주세요.

색인

이 명세에서 정의된 용어

참조에 의해 정의된 용어

참고 문헌

규범적 참고 문헌

[CSS-BACKGROUNDS-3]
Elika Etemad; Brad Kemper. CSS Backgrounds and Borders Module Level 3. 2024년 3월 11일. CR. URL: https://www.w3.org/TR/css-backgrounds-3/
[CSS-BORDERS-4]
CSS Borders and Box Decorations Module Level 4. 에디터 초안. URL: https://drafts.csswg.org/css-borders-4/
[CSS-BOX-4]
Elika Etemad. CSS Box Model Module Level 4. 2024년 8월 4일. WD. URL: https://www.w3.org/TR/css-box-4/
[CSS-CASCADE-5]
Elika Etemad; Miriam Suzanne; Tab Atkins Jr.. CSS Cascading and Inheritance Level 5. 2022년 1월 13일. CR. URL: https://www.w3.org/TR/css-cascade-5/
[CSS-COLOR-4]
Chris Lilley; Tab Atkins Jr.; Lea Verou. CSS Color Module Level 4. 2024년 2월 13일. CR. URL: https://www.w3.org/TR/css-color-4/
[CSS-CONTAIN-2]
Tab Atkins Jr.; Florian Rivoal; Vladimir Levin. CSS Containment Module Level 2. 2022년 9월 17일. WD. URL: https://www.w3.org/TR/css-contain-2/
[CSS-IMAGES-3]
Tab Atkins Jr.; Elika Etemad; Lea Verou. CSS Images Module Level 3. 2023년 12월 18일. CR. URL: https://www.w3.org/TR/css-images-3/
[CSS-MASKING-1]
Dirk Schulze; Brian Birtles; Tab Atkins Jr.. CSS Masking Module Level 1. 2021년 8월 5일. CR. URL: https://www.w3.org/TR/css-masking-1/
[CSS-OVERFLOW-3]
Elika Etemad; Florian Rivoal. CSS Overflow Module Level 3. 2023년 3월 29일. WD. URL: https://www.w3.org/TR/css-overflow-3/
[CSS-SCOPING-1]
Tab Atkins Jr.; Elika Etemad. CSS Scoping Module Level 1. 2014년 4월 3일. WD. URL: https://www.w3.org/TR/css-scoping-1/
[CSS-SIZING-3]
Tab Atkins Jr.; Elika Etemad. CSS Box Sizing Module Level 3. 2021년 12월 17일. WD. URL: https://www.w3.org/TR/css-sizing-3/
[CSS-SYNTAX-3]
Tab Atkins Jr.; Simon Sapin. CSS Syntax Module Level 3. 2021년 12월 24일. CR. URL: https://www.w3.org/TR/css-syntax-3/
[CSS-TRANSFORMS-1]
Simon Fraser; 등. CSS Transforms Module Level 1. 2019년 2월 14일. CR. URL: https://www.w3.org/TR/css-transforms-1/
[CSS-TRANSFORMS-2]
Tab Atkins Jr.; 등. CSS Transforms Module Level 2. 2021년 11월 9일. WD. URL: https://www.w3.org/TR/css-transforms-2/
[CSS-UI-4]
Florian Rivoal. CSS Basic User Interface Module Level 4. 2021년 3월 16일. WD. URL: https://www.w3.org/TR/css-ui-4/
[CSS-VALUES-4]
Tab Atkins Jr.; Elika Etemad. CSS Values and Units Module Level 4. 2024년 3월 12일. WD. URL: https://www.w3.org/TR/css-values-4/
[CSS-VIEW-TRANSITIONS-1]
Tab Atkins Jr.; Jake Archibald; Khushal Sagar. CSS View Transitions Module Level 1. 2024년 3월 28일. CR. URL: https://www.w3.org/TR/css-view-transitions-1/
[CSS22]
Bert Bos. Cascading Style Sheets Level 2 Revision 2 (CSS 2.2) Specification. 2016년 4월 12일. WD. URL: https://www.w3.org/TR/CSS22/
[CSSOM-1]
Daniel Glazman; Emilio Cobos Álvarez. CSS Object Model (CSSOM). 2021년 8월 26일. WD. URL: https://www.w3.org/TR/cssom-1/
[DOM]
Anne van Kesteren. DOM Standard. Living Standard. URL: https://dom.spec.whatwg.org/
[FILTER-EFFECTS-1]
Dirk Schulze; Dean Jackson. Filter Effects Module Level 1. 2018년 12월 18일. WD. URL: https://www.w3.org/TR/filter-effects-1/
[GEOMETRY-1]
Simon Pieters; Chris Harrelson. Geometry Interfaces Module Level 1. 2018년 12월 4일. CR. URL: https://www.w3.org/TR/geometry-1/
[HR-TIME-3]
Yoav Weiss. High Resolution Time. 2023년 7월 19일. WD. URL: https://www.w3.org/TR/hr-time-3/
[HTML]
Anne van Kesteren; 등. HTML Standard. Living Standard. URL: https://html.spec.whatwg.org/multipage/
[INFRA]
Anne van Kesteren; Domenic Denicola. Infra Standard. Living Standard. URL: https://infra.spec.whatwg.org/
[RFC2119]
S. Bradner. Key words for use in RFCs to Indicate Requirement Levels. 1997년 3월. Best Current Practice. URL: https://datatracker.ietf.org/doc/html/rfc2119
[SELECTORS-3]
Tantek Çelik; 등. Selectors Level 3. 2018년 11월 6일. REC. URL: https://www.w3.org/TR/selectors-3/
[SELECTORS-4]
Elika Etemad; Tab Atkins Jr.. Selectors Level 4. 2022년 11월 11일. WD. URL: https://www.w3.org/TR/selectors-4/
[WEBIDL]
Edgar Chen; Timothy Gu. Web IDL Standard. Living Standard. URL: https://webidl.spec.whatwg.org/

비규범적 참고 문헌

[CSS-CONDITIONAL-3]
Chris Lilley; David Baron; Elika Etemad. CSS Conditional Rules Module Level 3. 2024년 8월 15일. CR. URL: https://www.w3.org/TR/css-conditional-3/
[CSS-POSITION-3]
Elika Etemad; Tab Atkins Jr.. CSS Positioned Layout Module Level 3. 2024년 8월 10일. WD. URL: https://www.w3.org/TR/css-position-3/
[CSS-SHADOW-PARTS-1]
Tab Atkins Jr.; Fergal Daly. CSS Shadow Parts. 2018년 11월 15일. WD. URL: https://www.w3.org/TR/css-shadow-parts-1/

속성 색인

이름 초기값 적용 대상 상속 %값 애니메이션 타입 표준 순서 계산값
view-transition-class none | <custom-ident>+ none 모든 요소 아니오 해당 없음 불연속 문법 순서 명시값 그대로
view-transition-group normal | contain | nearest | <custom-ident> normal 모든 요소 아니오 해당 없음 불연속 문법 순서 명시값 그대로

@view-transition 디스크립터

이름 초기값
navigation auto | none none
types none | <custom-ident>+ none

IDL 색인

[Exposed=Window]
interface CSSViewTransitionRule : CSSRule {
  readonly attribute CSSOMString navigation;
  [SameObject] readonly attribute FrozenArray<CSSOMString> types;
};

[Exposed=Window]
interface ViewTransitionTypeSet {
  setlike<DOMString>;
};

[Exposed=Window]
partial interface ViewTransition {
  attribute ViewTransitionTypeSet types;
};

dictionary StartViewTransitionOptions {
  ViewTransitionUpdateCallback? update = null;
  sequence<DOMString>? types = null;
};

partial interface Document {
  ViewTransition startViewTransition(optional (ViewTransitionUpdateCallback or StartViewTransitionOptions) callbackOptions = {});
};

이슈 색인

이 동작을 CSS 속성으로 옵트인/옵트아웃 방식으로 제어해야 할까요? issue 11078 참고.
이전 상태 캡처가 여기서는 동기적 단계처럼 보이지만, 실제로는 요소를 이미지로 렌더링하는 것이 동기적으로 불가능하므로 비동기 단계입니다. 이 점을 L1 명세에서 더 명확히 해야 합니다.
overflow 및 containment의 동작을 명확히 해야 합니다. issue 11079 참고.