Blokowanie przewijania strony pod oknem modalnym

Gdy element <dialog> jest otwierany jako modal za pomocą showModal(), przeglądarka przenosi go do najwyższej warstwy i oznacza resztę dokumentu jako nieaktywną. Blokuje to kliknięcia wskaźnikiem i zaznaczenie klawiaturą na stronie pod spodem, ale nie uniemożliwia przewijania:

  1. Przewijanie, gdy wskaźnik lub gest dotykowy znajduje się nad elementem ::backdrop, powoduje przewijanie strony pod spodem.
  2. Przewijanie w elemencie <dialog> przechodzi do strony pod spodem, gdy okno osiągnie granicę przewijania, lub natychmiast, jeśli treść okna nie przepełnia go.

Zgodnie ze specyfikacją CSS Overscroll Behavior właściwość overscroll-behavior ma zastosowanie do wszystkich elementów kontenera przewijania, w tym do nieprzewijalnych kontenerów przewijania (elementów z overflow: hidden lub overflow: auto, których zawartość nie przepełnia obecnie kontenera). Łącząc overscroll-behavior: contain w <dialog> z overflow: hidden i overscroll-behavior: contain w dialog::backdrop, możesz zapobiec przewijaniu strony bazowej, używając tylko CSS.

Implementacja

1. Ograniczanie łańcucha przewijania w elemencie <dialog>

Arkusz stylów klienta użytkownika ustawia overflow: auto na <dialog>, co domyślnie czyni go kontenerem przewijania. Zastosuj overscroll-behavior: contain (lub none) do dialog:modal (lub dialog).

2. Przekształć element ::backdrop w kontener przewijania i ogranicz jego przewijanie

Domyślnie właściwość dialog::backdrop ma wartość overflow: visible, co oznacza, że nie jest to kontener z paskiem przewijania i ignoruje właściwość overscroll-behavior. Musisz ustawić overflow: hidden na dialog::backdrop, aby utworzyć nieprzewijalny kontener przewijania, i połączyć go z overscroll-behavior: contain, aby gesty przewijania wykonywane nad tłem były przechwytywane i nie docierały do dokumentu pod spodem.

Przykładowy kod

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

Sprawdzone metody i ograniczenia

  • OBOWIĄZKOWO: ustaw overscroll-behavior: contain w samym elemencie <dialog> (za pomocą selektora dialog:modal) i dialog::backdrop. Bez tej deklaracji gesty przewijania nad tłem lub w oknie dialogowym będą nadal powiązane ze stroną.
  • OBOWIĄZKOWE: ustaw overflow: hidden (lub overflow: auto) w dialog::backdrop, aby stał się kontenerem przewijania. Bez tej deklaracji ::backdrop domyślnie przyjmuje wartość overflow: visible, a overscroll-behavior nie będzie mieć żadnego efektu.
  • NIE używaj overflow: clip ani overflow: visible na dialog::backdrop ani dialog. Żadna z tych wartości nie tworzy kontenera przewijania, więc właściwość overscroll-behavior nie będzie stosowana.
  • NIE stosuj overflow: hidden ani position: fixed do <html> ani <body>, aby zablokować przewijanie tła po otwarciu okna. Mutowanie przepełnienia elementu głównego powoduje usunięcie paska przewijania strony (co powoduje przesunięcie układu w poziomie), może zresetować lub zmienić pozycję przewijania strony i może uszkodzić elementy position: sticky na stronie bazowej.

Strategie zastępcze

Właściwość CSS overscroll-behavior jest obsługiwana we wszystkich głównych przeglądarkach w przypadku kontenerów przewijania, które zawierają przepełnione treści, ale uwzględnianie właściwości overscroll-behavior w nieprzewijalnych kontenerach przewijania to nowsza specyfikacja, której nie można wykryć.

NIE próbuj wykrywać obsługi nieprzewijanych kontenerów za pomocą @supports (overscroll-behavior: contain) ani CSS.supports('overscroll-behavior', 'contain'). Wszystkie nowoczesne przeglądarki obsługują składnię właściwości overscroll-behavior: contain i zwracają true, nawet jeśli wymuszają ją tylko wtedy, gdy zawartość się przepełnia.

Zamiast tego traktuj ograniczenie przewijania w kontenerach, których nie można przewijać, jako progresywne ulepszanie:

  • W przeglądarkach, które obsługują overscroll-behavior w kontenerach przewijania, których nie można przewijać, przewijanie strony w tle jest całkowicie uniemożliwione zarówno nad dialog::backdrop, jak i wewnątrz <dialog> (niezależnie od tego, czy zawartość się przelewa).
  • W przeglądarkach, które nie obsługują jeszcze właściwości overscroll-behavior w kontenerach przewijania, których nie można przewijać, właściwość overscroll-behavior: contain w dialog nadal zapobiega łańcuchowemu przewijaniu, gdy zawartość okna dialogowego przepełnia się i można ją przewijać. Tymczasem showModal() nadal przechwytuje zaznaczenie klawiatury i oznacza dokument w tle jako inert.
  • Zalecamy korzystanie z progresywnego ulepszania zamiast starszych obejść, które stosują overflow: hidden lub position: fixed do <html> lub <body>, ponieważ nie usuwa ono głównego paska przewijania, nie powoduje przesunięć układu w poziomie, nie zmienia pozycji przewijania strony ani nie psuje elementów position: sticky na stronie bazowej.