게시일: 2025년 9월 22일
뷰 전환을 시작하면 브라우저가 view-transition-name로 태그된 요소의 전후 스냅샷을 자동으로 생성합니다. 이러한 스냅샷은 가상 요소 트리에서 렌더링됩니다. 기본적으로 생성된 트리는 '플랫'입니다. 즉, DOM의 원래 계층 구조가 손실되고 캡처된 모든 뷰 전환 그룹이 단일 ::view-transition 의사 요소 아래에 있는 동위 요소가 됩니다.
이 플랫 트리 접근 방식은 많은 사용 사례에 충분하지만, 이 방식으로 달성할 수 없는 스타일 지정 사용 사례도 있습니다. 다음은 플랫 트리에서 예상치 못한 시각적 효과를 일으킬 수 있는 효과의 예입니다.
- 클리핑 (
overflow,clip-path,border-radius): 클리핑은 요소의 하위 요소에 영향을 미칩니다. 즉, 뷰 전환 그룹 동위 요소는 서로를 클리핑할 수 없습니다. opacity,mask-image,filter: 마찬가지로 이러한 효과는 각 항목에 개별적으로 영향을 미치는 것이 아니라 하위 요소에 영향을 미치는 완전히 래스터화된 트리 이미지에서 작동하도록 설계되었습니다.- 3D 변환 (
transform-style,transform,perspective): 전체 범위의 3D 변환 애니메이션을 표시하려면 일부 계층 구조를 유지해야 합니다.
다음 예는 DOM 트리의 상위 요소에 의해 잘린 요소가 있는 플랫 의사 트리를 보여줍니다. 이러한 요소는 뷰 전환 중에 클리핑을 잃어 시각 효과가 손상됩니다.
중첩된 뷰 전환 그룹은 ::view-transition-group 가상 요소를 서로 중첩할 수 있는 뷰 전환의 확장 프로그램입니다. 뷰 전환 그룹이 중첩된 경우 전환 중에 클리핑과 같은 효과를 복원할 수 있습니다.
Browser Support
플랫 의사 트리에서 중첩된 의사 트리로
다음 데모에서는 사용자의 아바타를 클릭하여 해당 사용자에 대한 자세한 정보를 확인할 수 있습니다. 애니메이션은 클릭한 버튼을 대화상자로 변형하고, 화면에서 아바타와 이름을 이동하고, 대화상자에서 단락을 위 또는 아래로 슬라이드하는 동일 문서 뷰 전환으로 처리됩니다.
실시간 데모
데모 녹화
데모 녹음 (느린 버전)
데모를 자세히 살펴보면 전환에 문제가 있음을 알 수 있습니다. 설명이 포함된 단락이 DOM에서 <dialog> 요소의 하위 요소이지만 전환 중에 텍스트가 <dialog> 상자에 의해 잘리지 않습니다.
<dialog id="info_bramus" closedby="any">
<h2><img alt="…" class="avatar" height="96" width="96" src="avatar_bramus.jpg"> <span>Bramus</span></h2>
<p>Bramus is …</p>
<p>…</p>
</dialog>
<dialog>에 overflow: clip를 적용해도 아무런 효과가 없습니다.
문제는 뷰 전환이 의사 트리를 빌드하고 렌더링하는 방식입니다.
- 의사 트리에서 기본적으로 모든 스냅샷은 서로 동위입니다.
- 의사 트리는 전체 문서 위에 렌더링되는
::view-transition의사 요소에서 렌더링됩니다.
이 데모의 경우 DOM 트리는 다음과 같습니다.
html
├─ ::view-transition
│ ├─ ::view-transition-group(card)
│ │ └─ ::view-transition-image-pair(card)
│ │ ├─ ::view-transition-old(card)
│ │ └─ ::view-transition-new(card)
│ ├─ ::view-transition-group(name)
│ │ └─ ::view-transition-image-pair(name)
│ │ ├─ ::view-transition-old(name)
│ │ └─ ::view-transition-new(name)
│ ├─ ::view-transition-group(avatar)
│ │ └─ ::view-transition-image-pair(avatar)
│ │ ├─ ::view-transition-old(avatar)
│ │ └─ ::view-transition-new(avatar)
│ ├─ ::view-transition-group(paragraph1.text)
│ │ └─ ::view-transition-image-pair(paragraph1.text)
│ │ └─ ::view-transition-new(paragraph1.text)
│ └─ ::view-transition-group(paragraph2.text)
│ └─ ::view-transition-image-pair(paragraph2.text)
│ └─ ::view-transition-new(paragraph2.text)
├─ head
└─ body
└─ …
::view-transition-group(.text) 의사 요소는 ::view-transition-group(card) 의사 요소의 후속 동위 요소이므로 카드 위에 그려집니다.
::view-transition-group(card)가 ::view-transition-group(.text)를 클립하려면 ::view-transition-group(.text) 의사 요소가 ::view-transition-group(card)의 하위 요소여야 합니다. 이를 위해 생성된 ::view-transition-group() 가상 요소에 '상위 그룹'을 할당할 수 있는 view-transition-group를 사용합니다.
상위 그룹을 변경하는 방법에는 두 가지가 있습니다.
- 상위 요소에서
view-transition-group를contain로 설정하여view-transition-name가 있는 모든 하위 요소를 포함하도록 합니다. - 모든 하위 요소에서
view-transition-group를 상위 요소의view-transition-name로 설정합니다.nearest를 사용하여 가장 가까운 상위 그룹을 타겟팅할 수도 있습니다.
따라서 이 데모에서 중첩된 뷰 전환 그룹을 사용하려면 코드가 다음과 같이 됩니다.
button.clicked,
dialog {
view-transition-group: contain;
}
또는
button.clicked,
dialog *,
view-transition-group: nearest;
}
이 코드를 사용하면 ::view-transition-group(.text) 의사 요소가 이제 ::view-transition-group(card) 의사 요소 내에 중첩됩니다. 이는 모든 중첩된 의사 요소를 함께 유지하는 추가 ::view-transition-group-children(…) 의사 요소에서 실행됩니다.
html
├─ ::view-transition
│ ├─ ::view-transition-group(card)
│ │ ├─::view-transition-group-children(card)
│ │ │ ├─ ::view-transition-group(paragraph1.text)
│ │ │ │ └─ ::view-transition-image-pair(paragraph1.text)
│ │ │ │ └─ ::view-transition-new(paragraph1.text)
│ │ │ └─ ::view-transition-group(paragraph2.text)
│ │ │ └─ ::view-transition-image-pair(paragraph2.text)
│ │ │ └─ ::view-transition-new(paragraph2.text)
│ │ └─ ::view-transition-image-pair(card)
│ │ ├─ ::view-transition-old(card)
│ │ └─ ::view-transition-new(card)
│ ├─ ::view-transition-group(name)
│ │ └─ ::view-transition-image-pair(name)
│ │ ├─ ::view-transition-old(name)
│ │ └─ ::view-transition-new(name)
│ └─ ::view-transition-group(avatar)
│ └─ ::view-transition-image-pair(avatar)
│ ├─ ::view-transition-old(avatar)
│ └─ ::view-transition-new(avatar)
├─ head
└─ body
└─ …
마지막으로 ::view-transition-group(card) 가상 요소가 단락을 클리핑하도록 하려면 ::view-transition-group-children(card) 가상 요소에 overflow: clip를 적용합니다.
::view-transition-group-children(card) {
overflow: clip;
}
결과는 다음과 같습니다.
실시간 데모
데모 녹화
데모 녹음 (느린 버전)
::view-transition-group-children 가상은 중첩 그룹이 사용되는 경우에만 표시됩니다. 원래 요소의 테두리 상자에 맞게 크기가 조정되며, 이전 예시의 card와 같이 가상 요소를 생성한 요소와 동일한 모양과 테두리 두께를 가진 투명한 테두리가 지정됩니다.
클리핑 등
중첩된 뷰 전환 그룹은 클리핑 효과 이외의 위치에서 사용됩니다. 또 다른 예는 3D 효과입니다. 다음 데모에는 전환 중에 카드를 3D로 회전하는 옵션이 있습니다.
html:active-view-transition-type(open) {
&::view-transition-old(card) {
animation-name: rotate-out;
}
&::view-transition-new(card) {
animation-name: rotate-in;
}
}
html:active-view-transition-type(close) {
&::view-transition-old(card) {
animation-name: rotate-in;
}
&::view-transition-new(card) {
animation-name: rotate-out;
}
}
중첩된 뷰 전환 그룹이 없으면 아바타와 이름이 카드와 함께 회전하지 않습니다.
실시간 데모
데모 녹화
데모 녹음 (느린 버전)
아바타와 이름 의사 요소를 카드 내에 중첩하면 3D 효과를 복원할 수 있습니다. 하지만 이것이 전부는 아닙니다. ::view-transition-old(card) 및 ::view-transition-new(card) 의사 요소를 회전하는 것 외에도 ::view-transition-group-children(card) 의사 요소를 회전해야 합니다.
html:active-view-transition-type(open) {
&::view-transition-group-children(card) {
animation: rotate-in var(--duration) ease;
backface-visibility: hidden;
}
}
html:active-view-transition-type(close) {
&::view-transition-group-children(card) {
animation: rotate-out var(--duration) ease;
backface-visibility: hidden;
}
}
실시간 데모
데모 녹화
데모 녹음 (느린 버전)
데모 더보기
다음 예에서는 중첩된 뷰 전환 그룹을 사용하여 카드가 상위 스크롤러에 의해 잘리도록 합니다. 포함된 컨트롤을 사용하여 중첩된 뷰 전환 그룹의 사용을 사용 설정 또는 중지할 수 있습니다.
실시간 데모
데모 녹화
이 데모에서 흥미로운 점은 모든 ::view-transition-group(.card) 의사 요소가 상위 ::view-transition-group(cards) 의사 요소 내에 중첩되고 클리핑된다는 것입니다. #targeted-card은 진입/종료 애니메이션이 ::view-transition-group(cards)에 의해 잘리지 않아야 하므로 제외됩니다.
/* The .cards wrapper contains all children */
.cards {
view-transition-name: cards;
view-transition-group: contain;
}
/* Contents that bleed out get clipped */
&::view-transition-group-children(cards) {
overflow: clip;
}
/* Each card is given a v-t-name and v-t-class */
.card {
view-transition-name: match-element;
view-transition-class: card;
}
/* The targeted card is given a unique name (to style the pseudo differently)
and shouldn't be contained by the ::view-transition-group-children(cards) pseudo */
#targeted-card {
view-transition-name: targeted-card;
view-transition-group: none;
}
요약
중첩된 뷰 전환을 사용하면 의사 요소를 구성할 때 DOM 트리의 일부 토폴로지를 보존할 수 있습니다. 이렇게 하면 이전에는 뷰 전환으로 불가능했던 다양한 효과를 사용할 수 있으며, 그중 일부는 여기에서 설명합니다.
중첩은 뷰 전환이 구성되는 모델을 변경하며 고급 효과를 만드는 데 사용됩니다. 앞서 언급했듯이 요소 범위 뷰 전환은 더 간단한 모델로 효과의 하위 집합을 실행할 수도 있습니다. 두 기능을 모두 사용해 보고 필요에 가장 적합한 기능을 결정하는 것이 좋습니다.