ปิดกล่องโต้ตอบแบบ Light-Dismiss

ฟีเจอร์บนเว็บ: <dialog closedby>

กล่องโต้ตอบโมดัลสมัยใหม่มักรองรับ "การปิดแบบง่าย" ซึ่งช่วยให้ผู้ใช้ปิดกล่องโต้ตอบได้โดยคลิกหรือแตะฉากหลัง (พื้นที่นอกกล่องโต้ตอบ) แอตทริบิวต์ closedby เป็นวิธีประกาศเพื่อเปิดใช้ลักษณะการทำงานนี้โดยไม่ต้องใช้ JavaScript ที่กำหนดเอง

การใช้งาน

วิธีเปิดใช้การปิดเมื่อคลิกนอกองค์ประกอบ

  1. เพิ่ม closedby="any" ลงในองค์ประกอบ <dialog>
  2. เปิดกล่องโต้ตอบโดยใช้ dialog.showModal()

ค่าแอตทริบิวต์

  • any: เปิดใช้การปิดแบบง่าย (การคลิกฉากหลัง) "คำขอปิด" (แป้น Esc) และกลไกของนักพัฒนาซอฟต์แวร์ (เช่น dialog.close())
  • closerequest: เปิดใช้ "คำขอปิด" และกลไกของนักพัฒนาแอปเท่านั้น ซึ่งเป็นค่าเริ่มต้นสำหรับกล่องโต้ตอบโมดัล
  • none: มีเพียงกลไกของนักพัฒนาแอปเท่านั้นที่ปิดกล่องโต้ตอบได้

กำลังจัดรูปแบบฉากหลัง

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

/* Style the backdrop to indicate the dialog is modal */
dialog::backdrop {
  background-color: rgba(0, 0, 0, 0.5);
  backdrop-filter: blur(2px); /* Optional: add blur for modern browsers */
}

ตัวอย่าง

<!-- MANDATORY: Use closedby="any" to enable light-dismiss behavior -->
<dialog id="myDialog" closedby="any" aria-labelledby="dialogTitle">
  <form method="dialog">
    <h2 id="dialogTitle">Feedback</h2>
    <p>Click outside this box or press Esc to dismiss.</p>
    <button type="submit">Close</button>
  </form>
</dialog>

<button onclick="document.getElementById('myDialog').showModal()">Open Dialog</button>

ข้อจำกัดและการช่วยเหลือพิเศษ

  • บังคับ: ใช้ closedby="any" เพื่อเปิดใช้การปิดเมื่อคลิกนอกองค์ประกอบแบบประกาศ
  • บังคับ: เปิดกล่องโต้ตอบโมดัลด้วย showModal() เสมอ ซึ่งจะช่วยให้มั่นใจได้ว่ากล่องโต้ตอบจะอยู่ในเลเยอร์บนสุด โฟกัสจะถูกดักจับ และระบบจะจัดการแป้น Esc
  • ควรทำ: ใช้ aria-labelledby หรือ aria-label เพื่อระบุชื่อที่เข้าถึงได้สำหรับกล่องโต้ตอบ
  • อย่า: ใช้ closedby สำหรับกล่องโต้ตอบที่ไม่ใช่โมดัล (เปิดด้วย show()) เนื่องจากไม่มีฉากหลังและจะไม่ทริกเกอร์การปิดเมื่อคลิกนอกกล่องโต้ตอบ
  • อย่าใช้เหตุการณ์ click สำหรับตรรกะที่สำคัญซึ่งควรเกิดขึ้นก่อนปิด แต่ให้รอฟังเหตุการณ์ close หรือ cancel แทน

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

จำเป็น: สำหรับเบราว์เซอร์ที่ยังไม่รองรับ closedby คุณต้องใช้การสำรองสำหรับการปิดเมื่อคลิกนอกกล่องโต้ตอบโดยตรวจสอบว่ามีการคลิกนอกขอบเขตเนื้อหาของกล่องโต้ตอบหรือไม่โดยใช้สคริปต์ต่อไปนี้

const dialog = document.querySelector('dialog');

// Fallback for browsers without closedby support
if (!('closedBy' in HTMLDialogElement.prototype)) {
  dialog.addEventListener('click', (event) => {
    // 1. When clicking the backdrop, the event target is the dialog element itself.
    // Ignore clicks where the target is a child element inside the dialog.
    if (event.target !== dialog) return;

    // 2. Check if the click coordinates fall within the dialog's content box.
    // This distinguishes between a click on the backdrop vs a click on the dialog's background/padding.
    const rect = dialog.getBoundingClientRect();
    const isDialogContent = (
      rect.top <= event.clientY &&
      event.clientY <= rect.top + rect.height &&
      rect.left <= event.clientX &&
      event.clientX <= rect.left + rect.width
    );

    if (isDialogContent) return;

    // 3. Since the click was outside the content area (on the backdrop), manually close the dialog.
    dialog.close();
  });
}