Xuất bản: Ngày 22 tháng 9 năm 2025
Khi bạn bắt đầu một hoạt ảnh chuyển đổi khung hiển thị, trình duyệt sẽ tự động chụp ảnh nhanh trước và sau của các phần tử được gắn thẻ bằng view-transition-name
. Những ảnh chụp nhanh này được kết xuất trong một cây gồm các phần tử giả. Theo mặc định, cây được tạo là "phẳng". Điều này có nghĩa là hệ thống phân cấp ban đầu trong DOM sẽ bị mất và tất cả các nhóm chuyển đổi khung hiển thị được chụp đều là các phần tử ngang cấp trong một phần tử giả ::view-transition
duy nhất.
Phương pháp cây phẳng này đủ cho nhiều trường hợp sử dụng, nhưng có một số trường hợp sử dụng về kiểu dáng mà bạn không thể đạt được bằng phương pháp này. Sau đây là ví dụ về các hiệu ứng có thể có hiệu ứng hình ảnh không mong muốn trong cây phẳng:
- Cắt (
overflow
,clip-path
,border-radius
): thao tác cắt ảnh hưởng đến các phần tử con của phần tử, tức là các phần tử cùng cấp trong nhóm chuyển đổi khung hiển thị không thể cắt lẫn nhau. opacity
,mask-image
vàfilter
: tương tự, các hiệu ứng này được thiết kế để hoạt động trên hình ảnh được chuyển đổi hoàn toàn thành raster của một cây, ảnh hưởng đến các phần tử con thay vì ảnh hưởng đến từng mục riêng lẻ.- Phép biến đổi 3D (
transform-style
,transform
,perspective
): để hiển thị toàn bộ dải ảnh động biến đổi 3D, bạn cần duy trì một số hệ phân cấp.
Ví dụ sau đây cho thấy một cây giả phẳng, với các phần tử bị một phần tử tổ tiên cắt trong cây DOM. Các phần tử này mất đi phần cắt trong quá trình chuyển đổi khung hiển thị, dẫn đến hiệu ứng hình ảnh bị hỏng.
Nhóm chuyển đổi khung hiển thị lồng nhau là một phần mở rộng cho các hiệu ứng chuyển đổi khung hiển thị, cho phép bạn lồng các phần tử giả ::view-transition-group
vào nhau. Khi các nhóm chuyển đổi khung hiển thị được lồng vào nhau, bạn có thể khôi phục các hiệu ứng như cắt trong quá trình chuyển đổi.
Browser Support
Từ một cây giả phẳng đến một cây giả lồng nhau
Trong bản minh hoạ sau đây, bạn có thể nhấp vào hình đại diện của một người để xem thêm thông tin về người đó. Ảnh động được xử lý bằng một hiệu ứng chuyển đổi khung hiển thị trong cùng một tài liệu, giúp biến đổi nút đã nhấp thành hộp thoại, di chuyển hình đại diện và tên trên màn hình, đồng thời trượt các đoạn văn từ hộp thoại lên hoặc xuống.
Bản minh hoạ trực tiếp
Bản ghi minh hoạ
Bản ghi minh hoạ (Giảm tốc độ)
Nếu quan sát kỹ bản minh hoạ, bạn sẽ thấy có vấn đề với hiệu ứng chuyển đổi: mặc dù các đoạn văn có nội dung mô tả là phần tử con của phần tử <dialog>
trong DOM, nhưng văn bản không bị hộp <dialog>
cắt trong quá trình chuyển đổi:
<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>
Việc áp dụng overflow: clip
trên <dialog>
cũng không có tác dụng.
Vấn đề là cách chuyển đổi khung hiển thị tạo và kết xuất cây giả của chúng:
- Trong cây giả, theo mặc định, tất cả các ảnh chụp nhanh đều là anh chị em với nhau.
- Cây giả được kết xuất trong một phần tử giả
::view-transition
kết xuất trên đầu toàn bộ tài liệu.
Cụ thể đối với bản minh hoạ này, cây DOM sẽ có dạng như sau:
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
└─ …
Vì các ::view-transition-group(.text)
giả là các phần tử anh chị em kế tiếp của ::view-transition-group(card)
giả, nên chúng được vẽ ở trên cùng của thẻ.
Để có đoạn video ::view-transition-group(card)
::view-transition-group(.text)
, các giả chọn ::view-transition-group(.text)
phải là phần tử con của ::view-transition-group(card)
. Để làm việc này, hãy dùng view-transition-group
để chỉ định một "nhóm gốc" cho một phần tử giả ::view-transition-group()
được tạo.
Để thay đổi nhóm mẹ, bạn có 2 lựa chọn:
- Trên phần tử mẹ, hãy đặt
view-transition-group
thànhcontain
để phần tử này chứa tất cả các phần tử con cóview-transition-name
. - Trên tất cả các thành phần con, hãy đặt
view-transition-group
thànhview-transition-name
của thành phần mẹ. Bạn cũng có thể dùngnearest
để nhắm đến nhóm tổ tiên gần nhất.
Vì vậy, đối với bản minh hoạ này, để sử dụng các nhóm chuyển đổi khung hiển thị lồng nhau, mã sẽ là:
button.clicked,
dialog {
view-transition-group: contain;
}
Hoặc
button.clicked,
dialog *,
view-transition-group: nearest;
}
Khi mã này được đặt đúng vị trí, các giả ::view-transition-group(.text)
giờ sẽ được lồng bên trong giả ::view-transition-group(card)
. Việc này được thực hiện trong một ::view-transition-group-children(…)
giả bổ sung, giúp giữ tất cả các ::view-transition-group-children(…)
giả lồng nhau với nhau:
html
├─ ::view-transition
│ ├─ ::view-transition-group(card)
│ │ ├─ ::view-transition-image-pair(card)
│ │ │ ├─ ::view-transition-old(card)
│ │ │ └─ ::view-transition-new(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-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
└─ …
Cuối cùng, để ::view-transition-group(card)
cắt giả các đoạn văn, hãy áp dụng overflow: clip
lên ::view-transition-group-children(card)
giả:
::view-transition-group-children(card) {
overflow: clip;
}
Kết quả sẽ như sau:
Bản minh hoạ trực tiếp
Bản ghi minh hoạ
Bản ghi minh hoạ (Giảm tốc độ)
Giả ::view-transition-group-children
chỉ xuất hiện khi bạn dùng các nhóm lồng nhau. Nó được định cỡ theo border-box của phần tử ban đầu và có đường viền trong suốt với cùng hình dạng và độ dày đường viền như phần tử đã tạo phần tử giả – card
trong ví dụ trước.
Cắt và nhiều thao tác khác
Các nhóm chuyển đổi khung hiển thị lồng nhau được dùng ở những nơi khác ngoài hiệu ứng cắt. Một ví dụ khác là hiệu ứng 3D. Trong bản minh hoạ sau đây, bạn có thể xoay thẻ ở chế độ 3D trong quá trình chuyển đổi.
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;
}
}
Nếu không có các nhóm chuyển đổi khung hiển thị lồng nhau, hình đại diện và tên sẽ không xoay cùng với thẻ.
Bản minh hoạ trực tiếp
Bản ghi minh hoạ
Bản ghi minh hoạ (Giảm tốc độ)
Bằng cách lồng các giả lập tên và hình đại diện bên trong thẻ, hiệu ứng 3D có thể được khôi phục. Nhưng đó không phải là việc duy nhất bạn cần làm. Ngoài việc xoay các giả ::view-transition-old(card)
và ::view-transition-new(card)
, bạn cũng cần xoay giả ::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;
}
}
Bản minh hoạ trực tiếp
Bản ghi minh hoạ
Bản ghi minh hoạ (Giảm tốc độ)
Các bản minh hoạ khác
Trong ví dụ sau, các nhóm chuyển đổi khung hiển thị lồng nhau được dùng để đảm bảo các thẻ bị cắt bởi trình cuộn cấp trên. Bạn có thể bật hoặc tắt việc sử dụng các nhóm chuyển đổi khung hiển thị lồng nhau bằng các chế độ kiểm soát đi kèm.
Bản minh hoạ trực tiếp
Bản ghi minh hoạ
Điều thú vị về bản minh hoạ này là tất cả các giả ::view-transition-group(.card)
đều được lồng bên trong – và bị cắt bởi – giả ::view-transition-group(cards)
tổ tiên. #targeted-card
bị loại trừ vì hoạt ảnh xuất hiện/biến mất của thành phần này không được ::view-transition-group(cards)
cắt bớt.
/* 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;
}
Tóm tắt
Các hiệu ứng chuyển đổi khung hiển thị lồng nhau cho phép bạn giữ lại một số cấu trúc liên kết của cây DOM khi tạo các phần tử giả. Điều này mở ra nhiều hiệu ứng mà trước đây không thể thực hiện được bằng hiệu ứng chuyển đổi chế độ xem, một số hiệu ứng trong đó chúng tôi đã mô tả ở đây.
Việc lồng các thành phần sẽ thay đổi mô hình xây dựng hiệu ứng chuyển đổi khung hiển thị và được dùng để tạo các hiệu ứng nâng cao. Như đã lưu ý, các hiệu ứng chuyển đổi khung hiển thị theo phạm vi phần tử cũng có thể đạt được một số hiệu ứng với mô hình đơn giản hơn. Bạn nên dùng thử cả hai tính năng để quyết định xem tính năng nào phù hợp nhất với nhu cầu của mình.