เผยแพร่: 22 ก.ย. 2025
เมื่อคุณเริ่มการเปลี่ยนมุมมอง เบราว์เซอร์จะถ่ายภาพสแนปชอตก่อนและหลังขององค์ประกอบที่ติดแท็กด้วย view-transition-name
โดยอัตโนมัติ ระบบจะแสดงผลภาพรวมเหล่านี้ในโครงสร้างขององค์ประกอบเสมือน โดยค่าเริ่มต้น ต้นไม้ที่สร้างขึ้นจะ "แบน" ซึ่งหมายความว่าลำดับชั้นเดิมใน DOM จะหายไป และกลุ่มการเปลี่ยนมุมมองที่จับภาพทั้งหมดจะเป็นองค์ประกอบที่อยู่ระดับเดียวกันภายใต้::view-transition
องค์ประกอบเสมือนรายการเดียว
แนวทางแบบโครงสร้างแบนราบนี้เพียงพอสำหรับกรณีการใช้งานหลายอย่าง แต่ก็มีกรณีการใช้งานด้านการจัดรูปแบบบางอย่างที่ทำไม่ได้ด้วยแนวทางนี้ ตัวอย่างเอฟเฟกต์ที่อาจส่งผลภาพที่ไม่คาดคิดในโครงสร้างแบบแบนมีดังนี้
- การตัด (
overflow
,clip-path
,border-radius
): การตัดจะส่งผลต่อองค์ประกอบย่อย ซึ่งหมายความว่าองค์ประกอบที่อยู่ในกลุ่มการเปลี่ยนฉากเดียวกันจะตัดกันไม่ได้ opacity
,mask-image
และfilter
: ในทำนองเดียวกัน เอฟเฟกต์เหล่านี้ออกแบบมาให้ทำงานกับรูปภาพของต้นไม้ที่แรสเตอร์เต็มรูปแบบ โดยจะส่งผลต่อองค์ประกอบย่อยแทนที่จะส่งผลต่อแต่ละรายการแยกกัน- การเปลี่ยนรูปแบบ 3 มิติ (
transform-style
,transform
,perspective
): ต้องคงลำดับชั้นบางอย่างไว้เพื่อแสดงภาพเคลื่อนไหวการเปลี่ยนรูปแบบ 3 มิติทั้งหมด
ตัวอย่างต่อไปนี้แสดงโครงสร้างแบบลำดับชั้นเสมือนจริงที่มีองค์ประกอบซึ่งบรรพบุรุษในโครงสร้าง DOM ตัดออก องค์ประกอบเหล่านี้จะสูญเสียการครอบตัดระหว่างการเปลี่ยนมุมมอง ส่งผลให้เอฟเฟกต์ภาพเสีย
กลุ่มการเปลี่ยนมุมมองที่ซ้อนกันเป็นการขยายการเปลี่ยนมุมมองที่ช่วยให้คุณซ้อน::view-transition-group
องค์ประกอบเสมือนไว้ภายในกันได้ เมื่อซ้อนกลุ่มการเปลี่ยนฉาก คุณจะกู้คืนเอฟเฟกต์ต่างๆ เช่น การครอบตัด ในระหว่างการเปลี่ยนฉากได้
Browser Support
จากโครงสร้างแบบลำดับชั้นเทียมแบบแบนเป็นโครงสร้างแบบลำดับชั้นเทียมแบบซ้อนกัน
ในวิดีโอเดโมต่อไปนี้ คุณสามารถคลิกอวตารของบุคคลเพื่อดูข้อมูลเพิ่มเติมเกี่ยวกับบุคคลนั้นได้ ภาพเคลื่อนไหวจะได้รับการจัดการโดยการเปลี่ยนฉากมุมมองในเอกสารเดียวกัน ซึ่งจะเปลี่ยนปุ่มที่คลิกให้เป็นกล่องโต้ตอบ ย้ายอวตารและชื่อไปทั่วหน้าจอ และเลื่อนย่อหน้าจากกล่องโต้ตอบขึ้นหรือลง
การสาธิตการใช้งานแบบสด
การบันทึกการสาธิต
การบันทึกการสาธิต (ช้าลง)
หากดูการสาธิตอย่างละเอียด คุณจะเห็นว่าการเปลี่ยนผ่านมีปัญหา แม้ว่าย่อหน้าที่มีคำอธิบายจะเป็นองค์ประกอบย่อยขององค์ประกอบ <dialog>
ใน DOM แต่ข้อความจะไม่ถูกตัดโดยกล่องของ <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>
การใช้ overflow: clip
ใน <dialog>
ก็ไม่ได้ผลเช่นกัน
ปัญหาคือวิธีที่การเปลี่ยนฉากสร้างและแสดงผลแผนผังเสมือน
- ในโครงสร้างแบบลำดับชั้นเสมือน สแนปชอตทั้งหมดจะเป็นองค์ประกอบระดับเดียวกันโดยค่าเริ่มต้น
- ระบบจะแสดงผลโครงสร้างเสมือนใน
::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()
ที่สร้างขึ้นได้
คุณมี 2 ตัวเลือกในการเปลี่ยนกลุ่มหลัก ดังนี้
- ในองค์ประกอบหลัก ให้ตั้งค่า
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-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
└─ …
สุดท้าย หากต้องการให้ ::view-transition-group(card)
ตัดย่อหน้า ให้ใช้ overflow: clip
กับ ::view-transition-group-children(card)
ดังนี้
::view-transition-group-children(card) {
overflow: clip;
}
ผลลัพธ์ที่ได้มีดังนี้
การสาธิตการใช้งานแบบสด
การบันทึกการสาธิต
การบันทึกการสาธิต (ช้าลง)
::view-transition-group-children
pseudo จะแสดงเมื่อใช้กลุ่มที่ซ้อนกันเท่านั้น โดยมีขนาดเท่ากับ border-box ขององค์ประกอบเดิม และมีเส้นขอบโปร่งใสที่มีรูปร่างและความหนาของเส้นขอบเหมือนกับองค์ประกอบที่สร้างองค์ประกอบเสมือน ซึ่งก็คือ card
ในตัวอย่างก่อนหน้า
การตัดและการดำเนินการอื่นๆ
กลุ่มการเปลี่ยนฉากที่ซ้อนกันจะใช้ในที่อื่นๆ นอกเหนือจากเอฟเฟกต์การตัด อีกตัวอย่างหนึ่งคือเอฟเฟกต์ 3 มิติ ในการสาธิตต่อไปนี้มีตัวเลือกในการหมุนการ์ดในแบบ 3 มิติระหว่างการเปลี่ยน
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;
}
}
หากไม่มีกลุ่มการเปลี่ยนมุมมองที่ซ้อนกัน รูปโปรไฟล์และชื่อจะไม่หมุนไปพร้อมกับการ์ด
การสาธิตการใช้งานแบบสด
การบันทึกการสาธิต
การบันทึกการสาธิต (ช้าลง)
การซ้อนตัวอวตารและชื่อเสมือนไว้ในการ์ดจะช่วยให้เอฟเฟกต์ 3 มิติกลับมาทำงานได้ แต่คุณต้องทำมากกว่านั้น นอกจากการหมุน::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)
ไม่ควรตัดภาพเคลื่อนไหวเข้า/ออกของ #targeted-card
/* 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 ไว้ได้เมื่อสร้างองค์ประกอบเสมือน ซึ่งจะช่วยให้ใช้เอฟเฟกต์ต่างๆ ได้มากมายซึ่งก่อนหน้านี้ทำไม่ได้ด้วยการเปลี่ยนฉาก ซึ่งเราได้อธิบายบางส่วนไว้ที่นี่
การซ้อนจะเปลี่ยนรูปแบบการสร้างการเปลี่ยนฉากมุมมอง และมีไว้เพื่อใช้สร้างเอฟเฟกต์ขั้นสูง ดังที่ได้กล่าวไว้ การเปลี่ยนฉากของมุมมองที่กำหนดขอบเขตขององค์ประกอบยังสามารถสร้างเอฟเฟกต์บางส่วนได้ด้วยโมเดลที่เรียบง่ายกว่า เราขอแนะนำให้คุณลองใช้ทั้ง 2 ฟีเจอร์เพื่อดูว่าฟีเจอร์ใดเหมาะกับความต้องการของคุณมากที่สุด