เรียกใช้การเปลี่ยนฉากมุมมองพร้อมกันและแบบซ้อนกันด้วยการเปลี่ยนฉากมุมมองที่กำหนดขอบเขตขององค์ประกอบ

เผยแพร่: 27 มี.ค. 2026

การเปลี่ยนฉากมุมมองที่กำหนดขอบเขตขององค์ประกอบช่วยให้การเปลี่ยนฉากมุมมองหลายรายการทำงานพร้อมกันได้ อนุญาตให้การเปลี่ยนฉากมุมมองที่กำลังดำเนินการอยู่ซ้อนอยู่ภายในอีกรายการหนึ่ง และแก้ไขปัญหา z-index ที่คุณอาจพบกับการเปลี่ยนฉากมุมมองที่กำหนดขอบเขตของเอกสาร ทั้งหมดนี้ในขณะที่ส่วนอื่นๆ ของหน้ายังคงโต้ตอบได้ อ่านคู่มือนี้เพื่อดูวิธีใช้

วิดีโอโปรโมต: สร้างสรรค์เว็บใหม่ด้วยการเปลี่ยนมุมมองที่กำหนดขอบเขต ลองใช้การสาธิตแบบเรียลไทม์ (Chrome 147 ขึ้นไป)

ความจำเป็นในการเปลี่ยนฉากที่มีมุมมองที่กำหนดขอบเขตแคบลง

เมื่อคุณเริ่มการเปลี่ยนมุมมองเอกสารเดียวกันด้วย document.startViewTransition() (หรือผ่านการเปลี่ยนมุมมองเอกสารที่เกี่ยวข้อง) เบราว์เซอร์จะกำหนดขอบเขตการเปลี่ยนมุมมองที่ได้ไปยังเอกสาร

หลังจากที่เรียกใช้ Callback ของการอัปเดตและเบราว์เซอร์ถ่ายภาพรวมขององค์ประกอบที่จำเป็นทั้งหมดแล้ว ::view-transitionภาพซ้อนทับที่ได้และโครงสร้างขององค์ประกอบเสมือนจะแนบไปกับองค์ประกอบ :root html ในตัวอย่างต่อไปนี้

html
  ├─ ::view-transition
  │  └─ ::view-transition-group(root)
  │     └─ ::view-transition-image-pair(root)
  │        ├─ ::view-transition-old(root)
  │        └─ ::view-transition-new(root)
  ├─ head
  └─ body
     └─ …

เนื่องจากเลเยอร์ ::view-transition แสดงผลอยู่เหนือรูทของการเปลี่ยน จึงอาจทำให้เกิดสถานการณ์ที่ไม่คาดคิด เช่น องค์ประกอบที่เข้าร่วมการเปลี่ยนมุมมองอาจซ้อนทับกับองค์ประกอบอื่นๆ ที่ไม่ได้เข้าร่วมอย่างกะทันหัน หรือองค์ประกอบอาจไม่ถูกตัดโดยองค์ประกอบ Wrapper บรรพบุรุษอีกต่อไปในระหว่างการเปลี่ยนมุมมอง

การสาธิตการใช้งานแบบสด

การบันทึกการสาธิต

การเปิดใช้ pointer-events อีกครั้งใน ::view-transition หรือการใช้กลุ่มการเปลี่ยนฉากมุมมองที่ซ้อนกันจะช่วยแก้ผลข้างเคียงบางอย่างที่การเปลี่ยนฉากมุมมองที่กำหนดขอบเขตเอกสารทำให้เกิดได้ อย่างไรก็ตาม วิธีการเหล่านี้ไม่สามารถแก้ปัญหาได้ทั้งหมด

ตัวอย่างเช่น องค์ประกอบที่มี position: fixed หรือป๊อปโอเวอร์ยังคงถูกบดบังโดยการเปลี่ยนฉากมุมมองที่กำหนดขอบเขตเอกสารในขณะที่การเปลี่ยนฉากทำงานอยู่ ซึ่งเรียกอีกอย่างว่าปัญหา z-index

สลับป๊อปโอเวอร์ในเดโมต่อไปนี้ แล้วเลือกปุ่มสับเปลี่ยนเพื่อเริ่มการเปลี่ยนมุมมองระดับเอกสาร กลุ่มการเปลี่ยนมุมมองที่ซ้อนกันจะช่วยแก้ปัญหาการตัด แต่ปัญหาการซ้อนทับยังคงอยู่

การสาธิตการใช้งานแบบสด

การบันทึกการสาธิต

วิธีแก้ปัญหาอย่างหนึ่งคือการจับภาพ popover เป็นส่วนหนึ่งของการเปลี่ยนมุมมองโดยการกำหนด view-transition-name ให้ แม้ว่าวิธีนี้อาจใช้ได้กับอินสแตนซ์เดียว แต่ก็ดูแลรักษายากและทำให้กระบวนการสร้าง Snapshot ทำงานหนักโดยไม่จำเป็น

การเปลี่ยนฉากมุมมองที่กำหนดขอบเขตขององค์ประกอบ

การเปลี่ยนมุมมองที่กำหนดขอบเขตองค์ประกอบช่วยให้คุณเริ่มการเปลี่ยนมุมมองในส่วนย่อยของ DOM ได้ แทนที่จะเรียก document.startViewTransition() คุณจะเรียก element.startViewTransition() ในองค์ประกอบใดก็ได้ ซึ่งจะกำหนดขอบเขตการเปลี่ยนฉากของมุมมองไปยังองค์ประกอบนั้น

ในข้อมูลโค้ดต่อไปนี้ เบราว์เซอร์จะเริ่มการเปลี่ยนภาพมุมมองที่กำหนดขอบเขตองค์ประกอบในองค์ประกอบ <ul>

document.querySelector('ul').startViewTransition({
  callback: () => {
    // … code that manipulates the contents of <ul>
  },
})

องค์ประกอบที่คุณเรียกใช้ element.startViewTransition() เช่น <ul> เรียกว่ารูทการเปลี่ยนฉากหรือขอบเขต

เมื่อเบราว์เซอร์กำหนดขอบเขตการเปลี่ยนมุมมองเป็นองค์ประกอบ ระบบจะแยกองค์ประกอบนั้นออกจาก DOM ที่เหลือ

  • เบราว์เซอร์จะมองหาองค์ประกอบที่จะถ่ายภาพสแนปชอตภายในแผนผังย่อยของขอบเขตเท่านั้น
  • ในระหว่างกระบวนการสร้างสแนปชอต ขณะที่เรียกใช้ Callback update จะมีเพียงการแสดงผลขอบเขตเท่านั้นที่หยุดชั่วคราว
  • ::view-transition ที่ได้จะแทรกลงในรูทของการเปลี่ยน

ตัวอย่างเช่น เมื่อใช้ <ul> แผนผัง DOM จะมีลักษณะดังนี้ขณะที่การเปลี่ยนฉากของมุมมองทำงานอยู่

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

::view-transition Pseudo มีขนาดและรูปร่างเหมือนกับรูทของการเปลี่ยนฉาก และแสดงผลเฉพาะที่ด้านบนของรูทของการเปลี่ยนฉาก ด้วยเหตุนี้ ระบบจึงจะพิจารณาลำดับเลเยอร์ขององค์ประกอบที่อยู่นอกรูทของการเปลี่ยนฉาก

ตัวอย่างเช่น หากคุณมีป๊อปโอเวอร์ที่มองเห็นได้เหนือองค์ประกอบ <ul> แล้วเริ่มการเปลี่ยนฉากที่กำหนดขอบเขตองค์ประกอบในองค์ประกอบ <ul> ป๊อปโอเวอร์จะไม่ถูกบดบังโดยต้นไม้เสมือนของการเปลี่ยนฉาก

ลองใช้ในการสาธิตต่อไปนี้ โดยมีปุ่ม 2 ปุ่ม ปุ่มแรกจะสลับป๊อปโอเวอร์ และปุ่มที่ 2 จะจัดเรียงรายการใหม่โดยใช้การเปลี่ยนฉากมุมมองที่กำหนดขอบเขตขององค์ประกอบ

การสาธิตการใช้งานแบบสด

การบันทึกการสาธิต

เนื่องจากใช้การเปลี่ยนฉากมุมมองที่กำหนดขอบเขตขององค์ประกอบ ป๊อปโอเวอร์จึงยังคงปรากฏที่ด้านบนขององค์ประกอบ <ul> ขณะที่การเปลี่ยนฉากทำงานอยู่

นอกจากนี้ องค์ประกอบที่อยู่นอกองค์ประกอบ <ul> เช่น ปุ่ม จะยังคงโต้ตอบได้ เนื่องจากองค์ประกอบเหล่านั้นไม่ได้เป็นส่วนหนึ่งของขอบเขต

ขอบเขตการเข้าร่วมด้วยตนเองและกลุ่มการเปลี่ยนภาพที่ซ้อนกัน

เมื่อเริ่มการเปลี่ยนฉากมุมมองที่กำหนดขอบเขตองค์ประกอบในองค์ประกอบที่คลิปส่วนที่เกิน (กล่าวคือ เมื่อตั้งค่า overflow เป็น hidden, scroll หรือ clip) คุณจะเห็นว่าเนื้อหาของการเปลี่ยนฉากมุมมองยังคงถูกคลิปไว้

เนื่องจากการเปลี่ยนฉากมุมมองระดับองค์ประกอบจะจัดการสิ่งต่อไปนี้โดยอัตโนมัติ

  • ขอบเขตจะview-transition-name: rootมีผลโดยอัตโนมัติ ซึ่งทำให้ขอบเขตนั้นเข้าร่วมได้ด้วยตนเอง
  • ระบบจะใช้ขอบเขต view-transition-group: contain โดยอัตโนมัติเพื่อเปิดใช้กลุ่มการเปลี่ยนฉากมุมมองที่ซ้อนกัน
  • ::view-transition-group-children(root)เสมือนที่ได้จะตัดเนื้อหาโดยอัตโนมัติโดยใช้ overflow: clip หากรูทขอบเขตตัดส่วนที่เกิน ซึ่งจะป้องกันไม่ให้เสมือนแสดงภาพนอกรูทการเปลี่ยน

ด้วยเหตุนี้ คุณจึงสามารถใช้ CSS กับการเปลี่ยนมุมมองที่กำหนดขอบเขตองค์ประกอบโดยเน้นเฉพาะองค์ประกอบที่ต้องการจับภาพได้ ตัวอย่างเช่น ในการสาธิตรายการ CSS จะเพิ่มเฉพาะชื่อลงในรายการ

ul li {
  view-transition-name: match-element;
  view-transition-class: album;
}

ลองใช้ในการสาธิตต่อไปนี้ ซึ่งจะช่วยให้คุณลบล้างการเข้าร่วมด้วยตนเองได้ เมื่อขอบเขตเป็นการเข้าร่วมด้วยตนเอง (ลักษณะการทำงานเริ่มต้น) ทุกอย่างจะทำงานตามที่คาดไว้ เมื่อขอบเขตไม่ได้มีส่วนร่วมด้วยตนเอง ขอบเขตจะเปลี่ยนทันที และเนื้อหาจะล้นออกมาจาก Wrapper ในระหว่างการเปลี่ยน

การสาธิตการใช้งานแบบสด

การบันทึกการสาธิต

เพื่อเป็นข้อมูลอ้างอิง ต้นไม้แบบจำลองสำหรับการสาธิตนี้ที่มีการเข้าร่วมด้วยตนเองจะมีลักษณะดังนี้

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

เนื่องจากรูทของการเปลี่ยนฉาก ซึ่งก็คือองค์ประกอบ <ul> จะตัดเนื้อหาในแนวตั้ง ::view-transition-group-children(root) จึงใช้การตัดโดยอัตโนมัติด้วย

การเปลี่ยนภาพมุมมองที่กำหนดขอบเขตองค์ประกอบพร้อมกัน

เนื่องจากทรานซิชันมุมมองที่กำหนดขอบเขตองค์ประกอบจะทำงานแยกกัน ทรานซิชันมุมมองที่กำหนดขอบเขตองค์ประกอบหลายรายการจึงทำงานพร้อมกันได้หากมีขอบเขตต่างกัน

การสาธิตต่อไปนี้มีปุ่มจัดเรียงใหม่ 2 ปุ่ม ปุ่มละ 1 รายการ ปุ่มแต่ละปุ่มจะเริ่มการเปลี่ยนฉากมุมมองระดับองค์ประกอบในรายการที่เกี่ยวข้องเท่านั้น เนื่องจากแผนผัง DOM ของทั้ง 2 รายการไม่ทับซ้อนกัน การเปลี่ยนภาพมุมมองที่กำหนดขอบเขตขององค์ประกอบ 2 รายการจึงทำงานพร้อมกันได้โดยแยกกัน

การสาธิตการใช้งานแบบสด

การบันทึกการสาธิต

ลักษณะการแยกนี้ยังช่วยให้คุณนําค่า view-transition-name ไปใช้ซ้ำในขอบเขตต่างๆ ได้ด้วย ตราบใดที่ชื่อยังคงไม่ซ้ำกันภายในขอบเขตของชื่อนั้น ก็จะไม่มีความขัดแย้ง

การเปลี่ยนฉากมุมมองที่กำหนดขอบเขตองค์ประกอบที่ซ้อนกันและการจำกัดการใช้ view-transition-name

เมื่อ DOM Tree ของการเปลี่ยนภาพที่กำหนดขอบเขตองค์ประกอบหลายรายการทับซ้อนกัน จะมีความเสี่ยงที่ค่า view-transition-name จะชนกัน ด้วยเหตุนี้ เบราว์เซอร์จึงกำหนด view-transition-scope: all ให้กับการเปลี่ยนภาพวิวที่กำหนดขอบเขตขององค์ประกอบที่ใช้งานอยู่โดยอัตโนมัติเพื่อลดความเสี่ยงนี้

พร็อพเพอร์ตี้ view-transition-scope ช่วยให้มั่นใจได้ว่าค่า view-transition-name จะอยู่ในขอบเขตของ Subtree ขององค์ประกอบ เช่นเดียวกับที่ anchor-scope กำหนดขอบเขตค่า anchor-name พร็อพเพอร์ตี้ยอมรับ none รายชื่อที่คุณต้องการกำหนดขอบเขต หรือ all เพื่อกำหนดขอบเขตค่าทั้งหมด

นอกจากจะป้องกันไม่ให้ชื่อหลุดออกมาแล้ว view-transition-scope ยังป้องกันไม่ให้องค์ประกอบและเนื้อหาขององค์ประกอบนั้นถูกจับภาพโดยการเปลี่ยนภาพวิวภายนอกที่เกิดขึ้นพร้อมกันด้วย เมื่อกระบวนการสร้างสแนปชอตข้ามผ่านซับทรีเพื่อค้นหาองค์ประกอบที่จะสร้างสแนปชอต ระบบจะไม่สนใจองค์ประกอบ (และซับทรีทั้งหมดขององค์ประกอบ) ที่ใช้ view-transition-scope: all ซึ่งถือว่าองค์ประกอบเหล่านั้นเข้าร่วมการเปลี่ยนฉากที่กำหนดขอบเขตองค์ประกอบอื่นอยู่แล้ว

การสาธิตต่อไปนี้เป็นการดัดแปลงจากการสาธิตก่อนหน้า นอกจากปุ่ม 2 ปุ่มที่สุ่มเนื้อหาในรายการแล้ว ยังมีปุ่มสลับเพื่อสลับรายการด้วย การสลับ.reversedชั้นเรียนใน#lists-wrapperจะจัดการการสลับ

การสาธิตการใช้งานแบบสด

การบันทึกการสาธิต

เนื่องจากview-transition-scope: allจะใช้โดยอัตโนมัติในระหว่างการเปลี่ยนฉากแบบสุ่ม คุณจึงเริ่มการเปลี่ยนฉากแบบสลับด้านนอกพร้อมกันได้ในขณะที่การเปลี่ยนฉากแบบสุ่มยังคงดำเนินอยู่

เนื่องจาก view-transition-scope: all ยังป้องกันไม่ให้มีการถ่ายภาพรวมขององค์ประกอบในการเปลี่ยนฉากภายนอกด้วย เดโมจึงเพิ่มค่า view-transition-name ลงในองค์ประกอบที่รวมองค์ประกอบ <ul> ด้วย

#list1-wrapper, #list2-wrapper {
  view-transition-name: attr(id type(<custom-ident>));
}

แผนผังจำลองสำหรับการสาธิตนี้หลังจากเริ่มสุ่มในรายการที่ 2 แล้วสลับทั้ง 2 รายการจะมีลักษณะดังนี้

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

ดูข้อมูลเพิ่มเติม

ดูข้อมูลเพิ่มเติมเกี่ยวกับการเปลี่ยนฉากของมุมมองที่กำหนดขอบเขตขององค์ประกอบได้ที่คำอธิบาย ข้อกำหนด css-view-transitions-2 และรายการการแก้ไขข้อกำหนดที่เปิดอยู่