بستن کادر گفتگو با کلیک در خارج از آن

ویژگی‌های وب: <dialog closedby>

کادرهای گفتگوی وجهی مدرن اغلب از «بستن آسان» پشتیبانی می‌کنند که به کاربران اجازه می‌دهد با کلیک کردن یا ضربه زدن روی پس‌زمینه (ناحیه خارج از کادر گفتگو) کادر گفتگو را ببندند. مشخصه closedby روشی اعلانی برای فعال کردن این رفتار بدون جاوا اسکریپت سفارشی ارائه می‌دهد.

پیاده‌سازی

برای فعال کردن بستن با ضربه زدن:

  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();
  });
}