ป้องกันไม่ให้หน้าเว็บที่อยู่ใต้กล่องโต้ตอบโมดัลเลื่อน

ฟีเจอร์บนเว็บ: overscroll-behavior <dialog> ::backdrop :modal

เมื่อเปิดองค์ประกอบ <dialog> เป็นโมดัลโดยใช้ showModal() เบราว์เซอร์จะเลื่อนองค์ประกอบดังกล่าวไปยังเลเยอร์บนสุดและทำเครื่องหมายส่วนที่เหลือของเอกสารว่าไม่มีการทำงาน แม้ว่าการดำเนินการดังกล่าวจะบล็อกการคลิกเคอร์เซอร์และโฟกัสของแป้นพิมพ์ในหน้าเว็บที่อยู่ด้านล่าง แต่ก็ไม่ได้ป้องกันการเลื่อน

  1. การเลื่อนขณะที่เคอร์เซอร์หรือท่าทางสัมผัสอยู่เหนือ ::backdrop จะเลื่อนหน้าเว็บที่อยู่ด้านล่าง
  2. การเลื่อนภายใน <dialog> จะเชื่อมโยงไปยังหน้าเว็บที่อยู่ข้างใต้เมื่อกล่องโต้ตอบถึงขอบเขตการเลื่อน หรือทันทีหากเนื้อหาของกล่องโต้ตอบไม่ล้น

ตามข้อกำหนดลักษณะการทำงานของ Overscroll ใน CSS overscroll-behavior จะมีผลกับองค์ประกอบคอนเทนเนอร์การเลื่อนทั้งหมด รวมถึงคอนเทนเนอร์การเลื่อนที่เลื่อนไม่ได้ (องค์ประกอบที่มี overflow: hidden หรือ overflow: auto ซึ่งเนื้อหาไม่ล้นในปัจจุบัน) การรวม overscroll-behavior: contain ใน <dialog> เข้ากับ overflow: hidden และ overscroll-behavior: contain ใน dialog::backdrop จะช่วยป้องกันไม่ให้หน้าเว็บที่อยู่ด้านล่างเลื่อนโดยใช้ CSS ล้วนๆ

การใช้งาน

1. จำกัดการเชื่อมโยงการเลื่อนใน <dialog>

สไตล์ชีต User Agent จะตั้งค่า overflow: auto ใน <dialog> ซึ่งทำให้เป็นคอนเทนเนอร์แบบเลื่อนได้โดยค่าเริ่มต้น ใช้ overscroll-behavior: contain (หรือ none) กับ dialog:modal (หรือ dialog)

2. เปลี่ยน ::backdrop เป็นคอนเทนเนอร์แบบเลื่อนและจำกัดการเลื่อน

โดยค่าเริ่มต้น dialog::backdrop จะมี overflow: visible ซึ่งหมายความว่าไม่ใช่คอนเทนเนอร์แบบเลื่อนและไม่สนใจ overscroll-behavior คุณต้องตั้งค่า overflow: hidden ใน dialog::backdrop เพื่อทำให้เป็นคอนเทนเนอร์การเลื่อนที่เลื่อนไม่ได้ และจับคู่กับ overscroll-behavior: contain เพื่อให้ระบบดักจับท่าทางการเลื่อนที่ทำบนฉากหลังและไม่ไปถึงเอกสารด้านล่าง

โค้ดตัวอย่าง

dialog:modal {
  /* MANDATORY: Prevent scroll gestures inside the modal (even when its content
     does not overflow) from chaining to the underlying page. */
  overscroll-behavior: contain;
}

dialog::backdrop {
  /* MANDATORY: ::backdrop defaults to overflow: visible (not a scroll container).
     Set overflow: hidden so it becomes a non-scrollable scroll container that
     honors overscroll-behavior. */
  overflow: hidden;
  overscroll-behavior: contain;
}

แนวทางปฏิบัติแนะนำและข้อจำกัด

  • บังคับ: ตั้งค่า overscroll-behavior: contain ในองค์ประกอบ <dialog> เอง (โดยใช้ตัวเลือก dialog:modal) และ dialog::backdrop หากไม่มีการประกาศนี้ ท่าทางสัมผัสการเลื่อนเหนือฉากหลังหรือภายในกล่องโต้ตอบจะยังคงเชื่อมโยงกับหน้าเว็บ
  • จำเป็น: ตั้งค่า overflow: hidden (หรือ overflow: auto) ใน dialog::backdrop เพื่อให้กลายเป็นคอนเทนเนอร์แบบเลื่อน หากไม่มีการประกาศนี้ ::backdrop จะมีค่าเริ่มต้นเป็น overflow: visible และ overscroll-behavior จะไม่มีผล
  • อย่าใช้ overflow: clip หรือ overflow: visible ใน dialog::backdrop หรือ dialog ทั้ง 2 ค่าไม่ได้สร้างคอนเทนเนอร์การเลื่อน ดังนั้น overscroll-behavior จะไม่มีผล
  • อย่าใช้ overflow: hidden หรือ position: fixed กับ <html> หรือ <body> เพื่อล็อกการเลื่อนพื้นหลังเมื่อกล่องโต้ตอบเปิดขึ้น การเปลี่ยนแปลงโอเวอร์โฟลว์ของรูทจะนำแถบเลื่อนของหน้าออก (ทำให้เกิดการเปลี่ยนแปลงเลย์เอาต์ในแนวนอน) สามารถรีเซ็ตหรือข้ามตำแหน่งการเลื่อนหน้า และอาจทำให้องค์ประกอบ position: sticky ในหน้าเว็บที่อยู่ด้านล่างเสียหาย

กลยุทธ์สำรอง

แม้ว่าพร็อพเพอร์ตี้ CSS overscroll-behavior จะรองรับในเบราว์เซอร์หลักทั้งหมดสำหรับคอนเทนเนอร์การเลื่อนที่มีเนื้อหาล้น แต่การใช้ overscroll-behavior ในคอนเทนเนอร์การเลื่อนที่เลื่อนไม่ได้เป็นข้อกำหนดใหม่ที่ตรวจหาฟีเจอร์ไม่ได้

อย่าพยายามตรวจหาฟีเจอร์การรองรับคอนเทนเนอร์ที่เลื่อนไม่ได้ด้วย @supports (overscroll-behavior: contain) หรือ CSS.supports('overscroll-behavior', 'contain') เบราว์เซอร์ที่ทันสมัยทั้งหมดรองรับไวยากรณ์พร็อพเพอร์ตี้ overscroll-behavior: contain และแสดงผล true แม้ว่าจะบังคับใช้เฉพาะเมื่อเนื้อหาล้นก็ตาม

แต่ให้ถือว่าการจำกัดการเลื่อนในคอนเทนเนอร์การเลื่อนที่เลื่อนไม่ได้เป็นการเพิ่มประสิทธิภาพแบบต่อเนื่องแทน

  • ในเบราว์เซอร์ที่รองรับ overscroll-behavior ในคอนเทนเนอร์การเลื่อนที่เลื่อนไม่ได้ ระบบจะป้องกันการเลื่อนหน้าพื้นหลังอย่างสมบูรณ์ทั้งเหนือ dialog::backdrop และภายใน <dialog> (ไม่ว่าเนื้อหาจะล้นหรือไม่ก็ตาม)
  • ในเบราว์เซอร์ที่ยังไม่รองรับ overscroll-behavior ในคอนเทนเนอร์การเลื่อนที่เลื่อนไม่ได้ overscroll-behavior: contain ใน dialog จะยังคงป้องกันการเชื่อมโยงการเลื่อนเมื่อใดก็ตามที่เนื้อหาของกล่องโต้ตอบล้นและเลื่อนได้ ในขณะเดียวกัน showModal() ยังคงดักจับโฟกัสของแป้นพิมพ์และทำเครื่องหมายเอกสารพื้นหลังเป็น inert
  • เราขอแนะนำให้ใช้การเพิ่มประสิทธิภาพแบบต่อเนื่องแทนวิธีแก้ปัญหาแบบเดิมที่ใช้ overflow: hidden หรือ position: fixed กับ <html> หรือ <body> เนื่องจากวิธีนี้จะไม่นำแถบเลื่อนรูทออก ไม่ทำให้เลย์เอาต์แนวนอนเปลี่ยน ไม่ข้ามตำแหน่งการเลื่อนหน้าเว็บ หรือไม่ทำให้องค์ประกอบ position: sticky ในหน้าเว็บที่อยู่ด้านล่างเสียหาย