Ngày xuất bản: 27 tháng 3 năm 2026
Chuyển đổi chế độ xem theo phạm vi phần tử cho phép nhiều chuyển đổi chế độ xem chạy đồng thời, cho phép các chuyển đổi chế độ xem đang diễn ra được lồng trong một chuyển đổi khác và giải quyết các vấn đề về z-index mà bạn có thể gặp phải với chuyển đổi chế độ xem theo phạm vi tài liệu – tất cả đều giữ cho phần còn lại của trang có tính tương tác. Hãy đọc hướng dẫn này để tìm hiểu cách sử dụng các tính năng đó.
Nhu cầu về các hiệu ứng chuyển đổi chế độ xem phạm vi cụ thể có phạm vi hẹp hơn
Khi bạn bắt đầu chuyển đổi chế độ xem trong cùng một tài liệu bằng document.startViewTransition() (hoặc thông qua đối tượng tương ứng trên nhiều tài liệu), trình duyệt sẽ đặt phạm vi chuyển đổi chế độ xem kết quả cho tài liệu.
Sau khi lệnh gọi lại cập nhật thực thi và trình duyệt chụp nhanh tất cả các phần tử cần thiết, lớp phủ ::view-transition và cây gồm các phần tử giả kết quả sẽ gắn vào phần tử :root, html trong ví dụ sau.
html
├─ ::view-transition
│ └─ ::view-transition-group(root)
│ └─ ::view-transition-image-pair(root)
│ ├─ ::view-transition-old(root)
│ └─ ::view-transition-new(root)
├─ head
└─ body
└─ …
Vì lớp ::view-transition hiển thị ở trên cùng của gốc chuyển đổi, nên điều này có thể dẫn đến những tình huống không mong muốn. Ví dụ: các phần tử tham gia vào một lượt chuyển đổi khung hiển thị có thể đột ngột chồng lên các phần tử không tham gia khác hoặc các phần tử có thể không còn bị cắt bởi trình bao bọc tổ tiên của chúng trong quá trình chuyển đổi khung hiển thị.
Bản minh hoạ trực tiếp
Bản ghi minh hoạ
Bật lại pointer-events trên ::view-transition hoặc sử dụng các nhóm chuyển đổi khung hiển thị lồng nhau có thể giải quyết một số tác dụng phụ mà các hiệu ứng chuyển đổi khung hiển thị có phạm vi tài liệu mang lại. Tuy nhiên, những phương pháp này không thể giải quyết mọi vấn đề.
Ví dụ: các phần tử có position: fixed hoặc cửa sổ bật lên vẫn bị che khuất bởi hiệu ứng chuyển đổi khung hiển thị trong phạm vi tài liệu trong khi hiệu ứng chuyển đổi đang hoạt động – còn được gọi là vấn đề z-index.
Bật/tắt cửa sổ bật lên trong bản minh hoạ sau đây, rồi chọn nút Trộn để bắt đầu quá trình chuyển đổi chế độ xem theo phạm vi tài liệu. Các nhóm chuyển đổi khung hiển thị lồng nhau sẽ giải quyết vấn đề về việc cắt, nhưng vấn đề về việc phân lớp vẫn còn.
Bản minh hoạ trực tiếp
Bản ghi minh hoạ
Một giải pháp là chụp popover trong quá trình chuyển đổi khung hiển thị bằng cách đặt cho nó một view-transition-name. Mặc dù cách này có thể hoạt động cho một phiên bản duy nhất, nhưng việc duy trì sẽ rất rườm rà và gây áp lực không cần thiết cho quy trình chụp nhanh.
Chuyển đổi khung hiển thị theo phạm vi phần tử
Chế độ chuyển đổi khung hiển thị theo phạm vi phần tử cho phép bạn bắt đầu một chế độ chuyển đổi khung hiển thị trên một cây con của DOM. Thay vì gọi document.startViewTransition(), bạn gọi element.startViewTransition() trên một phần tử tuỳ ý, thao tác này sẽ đặt phạm vi chuyển đổi khung hiển thị thành phần tử đó.
Trong đoạn mã sau, trình duyệt sẽ bắt đầu một hiệu ứng chuyển đổi khung hiển thị có phạm vi phần tử trên phần tử <ul>.
document.querySelector('ul').startViewTransition({
callback: () => {
// … code that manipulates the contents of <ul>
},
})
Phần tử mà bạn gọi element.startViewTransition() (ví dụ: <ul>) được gọi là gốc chuyển đổi hoặc phạm vi.
Khi trình duyệt đặt phạm vi chuyển cảnh khung hiển thị cho một phần tử, phần tử đó sẽ tách biệt với phần còn lại của DOM:
- Trình duyệt chỉ tìm các phần tử để chụp nhanh trong cây con của phạm vi.
- Trong quá trình chụp nhanh (khi lệnh gọi lại
updatethực thi), chỉ quá trình kết xuất phạm vi bị tạm dừng. ::view-transitiongiả được tạo ra sẽ được chèn vào gốc chuyển đổi.
Ví dụ: với <ul>, cây DOM sẽ có dạng như sau trong khi hiệu ứng chuyển đổi khung hiển thị đang hoạt động:
html
├─ head
└─ body
├─ ul
│ ├─ ::view-transition
│ │ └─ ::view-transition-group(root)
│ │ ├─ ::view-transition-group-children(root)
│ │ │ └─ …
│ │ └─ ::view-transition-image-pair(root)
│ │ ├─ ::view-transition-old(root)
│ │ └─ ::view-transition-new(root)
│ ├─ li
│ ├─ li
│ └─ li
├─ button#showpopover
├─ button#reorder
└─ div#popover
└─ p
Giả ::view-transition có cùng kích thước và hình dạng với gốc chuyển đổi, đồng thời chỉ hiển thị ở trên cùng của gốc chuyển đổi. Do đó, thứ tự xếp lớp của các phần tử bên ngoài gốc chuyển đổi sẽ được tuân thủ.
Ví dụ: nếu bạn có một cửa sổ bật lên hiển thị phía trên phần tử <ul> rồi bắt đầu một hiệu ứng chuyển đổi chế độ xem có phạm vi phần tử trên phần tử <ul>, thì cửa sổ bật lên đó sẽ không bị che khuất bởi cây giả của hiệu ứng chuyển đổi chế độ xem.
Hãy thử trong bản minh hoạ sau. Thiết bị này có 2 nút. Nút đầu tiên bật/tắt cửa sổ bật lên và nút thứ hai sắp xếp lại các mục trong danh sách bằng hiệu ứng chuyển đổi khung hiển thị theo phạm vi phần tử.
Bản minh hoạ trực tiếp
Bản ghi minh hoạ
Vì các hiệu ứng chuyển đổi khung hiển thị theo phạm vi phần tử được dùng, nên cửa sổ bật lên vẫn hiển thị ở trên cùng của phần tử <ul> trong khi hiệu ứng chuyển đổi đang hoạt động.
Hơn nữa, các phần tử bên ngoài phần tử <ul> (ví dụ: các nút) vẫn có thể tương tác vì những phần tử đó không thuộc phạm vi.
Các phạm vi tự tham gia và các nhóm chuyển đổi khung hiển thị lồng nhau
Khi bắt đầu một hiệu ứng chuyển đổi khung hiển thị có phạm vi phần tử trên một phần tử cắt phần tràn (tức là khi overflow được đặt thành hidden, scroll hoặc clip), bạn sẽ nhận thấy rằng nội dung của hiệu ứng chuyển đổi khung hiển thị vẫn bị cắt về mặt hình ảnh.
Điều này là do các hiệu ứng chuyển đổi khung hiển thị theo phạm vi phần tử sẽ tự động xử lý những việc sau:
- Phạm vi này sẽ tự động được áp dụng
view-transition-name: root, nhờ đó, phạm vi này sẽ tự tham gia. - Phạm vi sẽ tự động được áp dụng
view-transition-group: containđể bật nhóm chuyển đổi chế độ xem lồng nhau. ::view-transition-group-children(root)giả kết quả sẽ tự động cắt nội dung bằngoverflow: clipnếu gốc phạm vi cắt phần tràn, điều này ngăn các phần tử giả tràn ra ngoài gốc chuyển đổi.
Do đó, bạn có thể chỉ tập trung CSS mà bạn dùng với các hiệu ứng chuyển đổi chế độ xem theo phạm vi phần tử vào những phần tử mà bạn muốn ghi lại. Ví dụ: trong bản minh hoạ danh sách, CSS chỉ thêm tên vào các mục trong danh sách:
ul li {
view-transition-name: match-element;
view-transition-class: album;
}
Hãy thử trong bản minh hoạ sau. Bạn có thể ghi đè chế độ tự tham gia. Khi phạm vi là tự tham gia (hành vi mặc định), mọi thứ sẽ hoạt động như dự kiến. Khi phạm vi không tự tham gia, đường viền của phạm vi đó sẽ thay đổi ngay lập tức và nội dung của phạm vi đó sẽ tràn ra khỏi trình bao bọc trong quá trình chuyển đổi.
Bản minh hoạ trực tiếp
Bản ghi minh hoạ
Để tham khảo, cây giả cho bản minh hoạ này có tính năng tự tham gia sẽ có dạng như sau:
html
├─ head
└─ body
├─ ul
│ ├─ ::view-transition
│ │ └─ ::view-transition-group(root)
│ │ ├─ ::view-transition-group-children(root)
│ │ │ ├─ ::view-transition-group(item1)
│ │ │ │ └─ ::view-transition-image-pair(item1)
│ │ │ │ ├─ ::view-transition-old(item1)
│ │ │ │ └─ ::view-transition-new(item1)
│ │ │ ├─ ::view-transition-group(item2)
│ │ │ │ └─ …
│ │ │ …
│ │ └─ ::view-transition-image-pair(root)
│ │ ├─ ::view-transition-old(root)
│ │ └─ ::view-transition-new(root)
│ ├─ li
│ ├─ li
│ └─ li
└─ button#reorder
Vì gốc chuyển đổi, phần tử <ul>, cắt nội dung theo chiều dọc nên ::view-transition-group-children(root) cũng tự động áp dụng một đoạn cắt.
Chuyển đổi chế độ xem đồng thời theo phạm vi phần tử
Vì các hiệu ứng chuyển đổi khung hiển thị theo phạm vi phần tử chạy riêng biệt, nên nhiều hiệu ứng chuyển đổi khung hiển thị theo phạm vi phần tử có thể chạy đồng thời nếu có phạm vi khác nhau.
Bản minh hoạ sau đây có 2 nút sắp xếp lại, mỗi nút cho một danh sách. Mỗi nút chỉ bắt đầu một hiệu ứng chuyển đổi chế độ xem theo phạm vi phần tử trên danh sách tương ứng. Vì cây DOM của cả hai danh sách không chồng chéo nhau, nên hai hiệu ứng chuyển đổi chế độ xem theo phạm vi phần tử có thể chạy đồng thời một cách riêng biệt.
Bản minh hoạ trực tiếp
Bản ghi minh hoạ
Tính chất riêng biệt này cũng cho phép bạn sử dụng lại các giá trị view-transition-name trên nhiều phạm vi. Miễn là tên vẫn là duy nhất trong phạm vi của nó, sẽ không có xung đột.
Hiệu ứng chuyển đổi chế độ xem có phạm vi phần tử lồng nhau và tính năng chứa view-transition-name
Khi cây DOM của nhiều hiệu ứng chuyển đổi chế độ xem theo phạm vi phần tử trùng lặp, sẽ có nguy cơ xảy ra xung đột giá trị view-transition-name. Vì lý do này, trình duyệt sẽ tự động chỉ định view-transition-scope: all cho các hiệu ứng chuyển đổi khung hiển thị có phạm vi là phần tử đang hoạt động để giảm thiểu rủi ro này.
Tương tự như cách anchor-scope đặt phạm vi cho các giá trị anchor-name, thuộc tính view-transition-scope đảm bảo rằng các giá trị view-transition-name đặt phạm vi cho cây con của phần tử. Thuộc tính này chấp nhận none, một danh sách tên mà bạn muốn đặt phạm vi hoặc all để đặt phạm vi cho tất cả các giá trị.
Ngoài việc ngăn tên bị rò rỉ, view-transition-scope cũng ngăn một phần tử và nội dung của phần tử đó bị một hiệu ứng chuyển đổi khung hiển thị đồng thời bên ngoài ghi lại. Khi quy trình chụp nhanh duyệt qua cây con để tìm một phần tử cần chụp nhanh, quy trình này sẽ bỏ qua những phần tử (và toàn bộ cây con của phần tử đó) đã áp dụng view-transition-scope: all. Điều này giả định rằng những phần tử đó đã tham gia vào một lượt chuyển đổi khung hiển thị theo phạm vi phần tử khác.
Bản minh hoạ sau đây là một biến thể của bản minh hoạ trước. Ngoài 2 nút trộn nội dung danh sách, ứng dụng này còn có nút Đổi để đổi danh sách. Việc bật/tắt một lớp .reversed trên #lists-wrapper sẽ xử lý việc hoán đổi.
Bản minh hoạ trực tiếp
Bản ghi minh hoạ
Vì view-transition-scope: all tự động áp dụng trong quá trình chuyển đổi xáo trộn, nên bạn có thể bắt đầu một quá trình chuyển đổi hoán đổi đồng thời, bên ngoài trong khi quá trình chuyển đổi xáo trộn vẫn đang diễn ra.
Vì view-transition-scope: all cũng ngăn không cho một phần tử được chụp nhanh trong một hiệu ứng chuyển đổi bên ngoài, nên bản minh hoạ cũng thêm các giá trị view-transition-name vào các phần tử bao bọc các phần tử <ul>.
#list1-wrapper, #list2-wrapper {
view-transition-name: attr(id type(<custom-ident>));
}
Cây giả cho bản minh hoạ này, sau khi bắt đầu một thao tác trộn trên danh sách thứ hai rồi hoán đổi cả hai danh sách, sẽ có dạng như sau:
html
├─ head
└─ body
└─ #lists-wrapper.reversed (SCOPE)
├─ ::view-transition
│ └─ ::view-transition-group(lists-wrapper)
│ ├─ ::view-transition-group-children(lists-wrapper)
│ │ ├─ ::view-transition-group(list1-wrapper)
│ │ │ └─ ::view-transition-image-pair(list1-wrapper)
│ │ │ ├─ ::view-transition-old(list1-wrapper)
│ │ │ └─ ::view-transition-new(list1-wrapper)
│ │ └─ ::view-transition-group(list2-wrapper)
│ │ └─ ::view-transition-image-pair(list2-wrapper)
│ │ ├─ ::view-transition-old(list2-wrapper)
│ │ └─ ::view-transition-new(list2-wrapper)
│ └─ ::view-transition-image-pair(lists-wrapper)
│ ├─ ::view-transition-old(lists-wrapper)
│ └─ ::view-transition-new(lists-wrapper)
├─ div#list1-wrapper
│ ├─ ul
│ │ ├─ li#item1
│ │ ├─ li#item2
│ │ └─ li#item3
│ └─ button.reorder
└─ div#list2-wrapper
├─ ul (SCOPE)
│ ├─ ::view-transition
│ │ └─ ::view-transition-group(list)
│ │ ├─ ::view-transition-group-children(list )
│ │ │ ├─ ::view-transition-group(item4)
│ │ │ │ └─ ::view-transition-image-pair(item4)
│ │ │ │ ├─ ::view-transition-old(item4)
│ │ │ │ └─ ::view-transition-new(item4)
│ │ │ ├─ ::view-transition-group(item5)
│ │ │ │ └─ …
│ │ │ …
│ │ └─ ::view-transition-image-pair(list)
│ │ ├─ ::view-transition-old(list)
│ │ └─ ::view-transition-new(list)
│ ├─ li#item4
│ ├─ li#item5
│ └─ li#item6
└─ button.reorder
Tìm hiểu thêm
Để tìm hiểu thêm về hiệu ứng chuyển đổi chế độ xem theo phạm vi phần tử, hãy xem phần giải thích, quy cách css-view-transitions-2 và danh sách các nội dung chỉnh sửa quy cách mở.