İletişim Kutusu

Genel Bakış

Kalıcı ve kalıcı olmayan iletişim kutuları için yerel <dialog> öğesini kullanın. Özel yer paylaşımlarının manuel olarak yeniden oluşturması gereken erişilebilirlik semantiği, odak işleme, üst katman oluşturma ve Esc işleme özelliklerini sağlar.

Yer paylaşımı türünü seçme

Eşleşen ilk kuralı seçin. Emin değilseniz 1. kuralı kullanın.

1. kural: Yer paylaşımı, kullanıcının deneyimini kesintiye uğratır ve sayfayı engeller (varsayılan)

Onaylar, formlar, oturum açma, yıkıcı işlemler ve aksi belirtilmeyen tüm "kalıcı", "iletişim kutusu", "lightbox" veya "pop-up" istekleri için kullanın.

<dialog> öğesini kalıcı olarak açılmış şekilde, command="show-modal" ile bildirimli olarak (Bildirimli İletişim Kutusu ve Popover Kontrolü bölümüne bakın) veya showModal() ile komut dosyasından kullanın.

<button type="button" command="show-modal" commandfor="confirm">Delete</button>

<!-- MANDATORY: no role="dialog" or aria-modal; the native modal already provides them -->
<dialog id="confirm" aria-labelledby="confirm-title">
  <h2 id="confirm-title">Delete this item?</h2>
  <form method="dialog">
    <button value="cancel" autofocus>Cancel</button>
    <button value="delete">Delete</button>
  </form>
</dialog>

Tarayıcı; inert sayfa, odak sınırlama, üst katman, ::backdrop, Esc ve geri hareketiyle kapatma ve odağın çağırana geri dönmesini sağlar.

  • role="dialog", aria-modal, odak tuzağı, inert açma/kapatma veya Esc işleyici EKLEMEYİN.
  • show() veya open özelliğiyle açmayın.
  • DO stop the page scrolling behind it with the CSS below. Ayrıntılar için Kalıcı iletişim kutusunun altındaki sayfanın kaydırılmasını önleme başlıklı makaleyi inceleyin.
  • html veya body üzerinde overflow: hidden ya da position: fixed ile kaydırmayı KİLİTLEMEYİN.
/* MANDATORY (both rules): without them, scrolling over the backdrop or inside the dialog scrolls the page behind it */
dialog:modal {
  overscroll-behavior: contain; /* stops scroll gestures in the dialog chaining to the page */
}
dialog::backdrop {
  overflow: hidden; /* ::backdrop is not a scroll container by default, so it would ignore overscroll-behavior */
  overscroll-behavior: contain;
}

Menüler veya ipuçları için kullanılmaz: 3. kurala bakın.

2. kural: Panel açıkken kullanıcı sayfada çalışmaya devam eder

Anlamsal olarak hâlâ iletişim kutusu olan bulma çubukları, denetleyiciler, paletler ve oluşturma bölmeleri için kullanılır.

Pop-over kapatma özelliğine sahip üst katman paneli için <dialog popover> kullanın (auto hafif kapatma özelliğine sahiptir, manual ise yoktur). dialog.show() özelliğini yalnızca panelin üst katmanda olmaması gerektiğinde kullanın.

<button type="button" popovertarget="find">Find</button>
<dialog id="find" popover="manual" aria-labelledby="find-title">
  <h2 id="find-title">Find</h2>
  <input type="search" aria-label="Search">
  <button type="button" popovertarget="find" popovertargetaction="hide">Close</button>
</dialog>

Sayfa etkileşimli kalır ve devre dışı bırakılmaz.

  • Görünür bir kapat düğmesi EKLEYİN.
  • Sayfayı engelleyen showModal() yönergesini KULLANMAYIN.

Onayları engellemek için kullanılmaz: 1. kurala bakın.

3. kural: Yer paylaşımı bir iletişim kutusu değildir

Menüler, açılır listeler, ipuçları, fareyle üzerine gelindiğinde gösterilen kartlar ve kısa süreli bildirimler için kullanılır.

<dialog> yerine popover özelliğine sahip bir semantik öğe kullanın.

<button type="button" popovertarget="menu">Actions</button>
<ul id="menu" popover>
  <li><a href="/rename">Rename</a></li>
</ul>

Nasıl kapatılabileceğini seçin

Varsayılan yöntem, iletişim kutusunun nasıl açıldığına bağlıdır. closedby yoksa veya geçersizse showModal(), closerequest olarak davranır ve diğer açma yöntemleri none olarak davranır.

  • Yalnızca Esc ve geri hareketi (kalıcı varsayılan): Hiçbir şey ayarlamayın veya closedby="closerequest".
  • Kapatmak için dışarıyı da tıklayabilirsiniz: closedby="any" kullanın.
  • Yalnızca geliştirici kapatır (örneğin, kaydedilmemiş değişiklikler içeren bir form): closedby="none" kullanın ve bir onay yolu ekleyin. Aşağıdaki "Kapanış" bölümüne bakın.

Yönergeler

Erişilebilir özellikli ad ve ilk odaklanılan nokta

  • Her iletişim kutusunu, başlığına işaret eden aria-labelledby ile veya görünür bir başlık yoksa aria-label ile adlandırın.
  • autofocus öğesini birincil kontrole veya ilk alana YERLEŞTİRİN.
  • Yıkıcı bir onayda güvenli işleme (İptal veya Sakla gibi) autofocus EKLEYİN.
  • Kapatma işleminde odağı geri döndürmek için kod YAZMAYIN. Tarayıcı, bu değeri çağırana döndürür.

Açılma

Kapanma

  • DO close with <form method="dialog"> buttons or command="close".
  • closedby değerini bilinçli olarak seçin: any (hafif kapatma ve Esc), closerequest (yalnızca Esc, kalıcı varsayılan) veya none (yalnızca geliştirici tarafından kontrol edilen kapatma).
  • Kaydedilmemiş değişiklikler mantığına uyması gereken İptal düğmeleri için command="request-close" veya requestClose() KULLANIN. Önce cancel tetiklenir ve closedby yok sayılır.
  • closedby özelliğini progresif geliştirme olarak KULLANIN. Esc ve mobil geri hareketi, bu özellik olmadan da modalları kapatıyor.

Kapatma işlemine bağlanma

  • Hangi düğmenin kullanıldığını öğrenmek için dialog.returnValue değerini bir close dinleyicide OKUYUN, ardından dialog.returnValue = '' ile sıfırlayın. Esc ve diğer kapatma istekleri değer ayarlamaz ve tarayıcılar önceki değeri temizleyip temizlememe konusunda farklılık gösterir. Bu nedenle, sıfırlama yapılmazsa eski bir değer sızdırılabilir. '', "seçim yapılmadan kapatıldı" olarak değerlendirilir.
  • DO use cancel to intercept Esc and request-close, but do not rely on preventDefault() for repeated Esc presses without user activation.
  • Kirli formlar için açık bir onay adımıyla closedby="none" KULLANIN.
  • cancel engellendiğinde iletişim kutusunun neden açık kaldığını kullanıcıya SÖYLEYİN: Görünür bir mesaj gösterin ve odaklanan kontrolden (ör. Sil) aria-describedby ile bu mesaja referans verin. Böylece odak taşındığında ekran okuyucu bu mesajı okur. Bu özellik olmadan, odak yeni bir düğmeye taşındığında yalnızca o düğmenin adı duyurulur.
  • Onay taşıma kontrollerinin işaretçinin altında kalmasına İZİN VERMEYİN. Mesajın alanını ayırın (display veya hidden ile değil, visibility ile gizleyin) ve yıkıcı düğmeyi mevcut düğmelerin hareket etmeyeceği bir yere (örneğin, sağa hizalı bir satırda ilk sıraya) ekleyin. Böylece aynı noktaya ikinci kez tıklandığında kullanıcının değişiklikleri silinmez.

Kalıcı olmayan iletişim kutuları

  • Üst katman panel için <dialog popover> (auto veya manual) ve üst katmanı istemediğinizde dialog.show() KULLANIN.
  • Kalıcı olmayan her iletişim kutusuna görünür bir kapatma düğmesi EKLEYİN.

Arka plan ve stil

Erişilebilirlik

  • role="dialog", aria-modal, manuel odaklama tuzağı veya yerel bir kalıcı pencereye geçiş yapan inert EKLEMEYİN.
  • Kapatma kontrolleri için erişilebilir özellikli adı olan yerel bir <button> KULLANIN.
  • İletişim kutusu başlıkları için tek bir tutarlı başlık düzeyi KULLANIN.

Yedek stratejiler

closedby (dialog-closedby)

closedby olmadan da kalıcı pencere Esc ve geri hareketiyle kapatılabilir. Yalnızca dışarı tıklama özelliği kullanılamaz. Bu nedenle, bu durum kontrollü azalma olarak kabul edilir. closedby="none" da aynı şekilde yoksayılır: Esc, cancel işlemini tetikler ve ardından iletişim kutusunu kapatır. Kaydedilmemiş değişiklik korumasını yalnızca closedby="none" içinde değil, cancel işleyicisinde tutun. Böylece closedby eksik olduğunda da koruma sağlanır. Baseline hedefiniz için hafif kapatma gerekiyorsa closedby eksik olan yere şunu ekleyin:

if (!('closedBy' in HTMLDialogElement.prototype)) {
  // Test the pointer position, not event.target: the <dialog> is also the target for its own
  // padding and the gaps between its children, so a target check would close on those clicks
  const outside = (e, dialog) => {
    const r = dialog.getBoundingClientRect();
    return e.clientX < r.left || e.clientX > r.right || e.clientY < r.top || e.clientY > r.bottom;
  };
  for (const dialog of document.querySelectorAll('dialog[closedby="any"]')) {
    let pressedOutside = false;
    dialog.addEventListener('pointerdown', (e) => { pressedOutside = outside(e, dialog); });
    // Require the press and the release outside, so a text-selection drag that ends on the backdrop does not dismiss
    dialog.addEventListener('pointerup', (e) => { if (pressedOutside && outside(e, dialog)) dialog.close(); });
  }
}

overscroll-behavior

Kaydırma sınırlamasını progresif geliştirme olarak değerlendirin. Özellik algılama kullanmayın: @supports, kaydırılamayan kapsayıcılar tarafından yoksayılsa bile özelliği destekleniyor olarak bildirir. Uygulanmadığı durumlarda, iletişim kutusu kendi içeriği taştığında kaydırma çubuğunu içerir ve showModal(), sayfayı yine de devre dışı bırakır. html veya body üzerinde overflow: hidden ya da position: fixed değerine geri dönmeyin. Bu, kök kaydırma çubuğunu kaldırır ve düzeni değiştirir.

Çağırıcı Komutları (command / commandfor)

Baseline hedefiniz Invoker Commands'i içermiyorsa aynı işaretlemeyi kullanın ve polyfill'i koşullu olarak yükleyin (progresif geliştirme ile aynı deneyim). Arayüzde algılayın ve hiçbir zaman koşulsuz olarak yüklemeyin:

// MANDATORY: feature detect on HTMLButtonElement.prototype and load only when native support is missing
if (!('commandForElement' in HTMLButtonElement.prototype)) {
  import('invokers-polyfill'); // npm install invokers-polyfill
}

Yalnızca 2. ve 3. kurallarda popover kullanılır.

Popover için yedekler ve tarayıcı desteği

Popover API çoğunlukla progresif geliştirme ile ilgilidir ancak tanımlayıcı davranışlarının (üst katman tanıtımı, hafif kapatma ve popovertarget çağrısı) yalnızca CSS'ye dayalı bir eşdeğeri yoktur. Eski tarayıcılar için polyfill veya polyfill kullanmak istemiyorsanız manuel yedek gerekir.

Polyfill: Eski tarayıcılarda popover özelliğini desteklemek için @oddbird/popover-polyfill öğesini koşullu olarak yükleyin. ZORUNLU: HTMLElement.prototype üzerinde popover özelliğini kontrol ederek özelliği tespit edin ve polyfill'i yalnızca yerel destek eksik olduğunda yükleyin. Koşulsuz olarak YÜKLEMEYİN.

Paketleyici veya içe aktarma eşlemesiyle:

// MANDATORY: Feature detect 'popover' on HTMLElement.prototype.
if (!("popover" in HTMLElement.prototype)) {
  import("@oddbird/popover-polyfill");
}

Paketleyici olmadan, <script type="module"> içindeki bir CDN'den içe aktarın:

<script type="module">
  if (!("popover" in HTMLElement.prototype)) {
    import("https://unpkg.com/@oddbird/popover-polyfill@latest/dist/popover.min.js");
  }
</script>

Stil uyarısı: Polyfill, gerçek :popover-open sözde sınıfını tanımlayamadığı için bunun yerine .\:popover-open sınıfını uygular. ZORUNLU: İkisini :is() veya :where() ile birleştirin. Aksi takdirde, :popover-open içermeyen tarayıcılar kuralın tamamını siler:

[popover]:is(:popover-open, .\:popover-open) {
  display: block;
}

Alternatif olarak, polyfill içermeyen eski bir yedek için position: fixed kullanın ve koordinatları getBoundingClientRect() aracılığıyla manuel olarak hesaplayın veya kullanım alanına uygunsa inset: auto ile varsayılan konumlandırmayı kullanın.