מניעת גלילה בדף שמתחת לתיבת דו-שיח מודאלית

תכונות אינטרנט: overscroll-behavior <dialog> ::backdrop :modal

כשפותחים רכיב <dialog> כמודל באמצעות showModal(), הדפדפן מקדם אותו לשכבה העליונה ומסמן את שאר המסמך כלא פעיל. הפעולה הזו חוסמת קליקים של מצביע העכבר ומיקוד מקלדת בדף שמתחת, אבל לא מונעת גלילה:

  1. גלילה בזמן שהסמן או תנועת המגע נמצאים מעל ::backdrop גורמת לגלילה של הדף שמתחת.
  2. גלילה בתוך <dialog> עוברת לדף שמתחת ברגע שתיבת הדו-שיח מגיעה לגבול הגלילה שלה, או באופן מיידי אם התוכן של תיבת הדו-שיח לא חורג מהגבולות.

בהתאם למפרט של התכונה CSS Overscroll Behavior, הערך overscroll-behavior חל על כל הרכיבים של מאגרי גלילה, כולל מאגרי גלילה שלא ניתנים לגלילה (רכיבים עם overflow: hidden או overflow: auto שהתוכן שלהם לא חורג כרגע). אם משלבים את overscroll-behavior: contain ב-<dialog> עם overflow: hidden ו-overscroll-behavior: contain ב-dialog::backdrop, אפשר למנוע את הגלילה של הדף הבסיסי באמצעות CSS בלבד.

הטמעה

1. הכלת שרשור גלילה ב-<dialog>

גיליון הסגנונות של סוכן המשתמש מגדיר את 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. אף אחד מהערכים לא יוצר מאגר גלילה, ולכן המאפיין overscroll-behavior לא יחול.
  • אל תפעילו את overflow: hidden או את position: fixed על <html> או על <body> כדי לנעול את הגלילה ברקע כשתיבת דו-שיח נפתחת. שינוי של גלישת הטקסט ברכיב הבסיסי מסיר את סרגל הגלילה של הדף (מה שגורם לשינוי בפריסה האופקית), יכול לאפס את מיקום הגלילה בדף או לגרום לו לקפוץ, ויכול לשבש רכיבי position: sticky בדף שמתחת.

שיטות חלופיות

המאפיין overscroll-behavior ב-CSS נתמך בכל הדפדפנים העיקריים במאגרי גלילה עם תוכן שחורג מהגבולות, אבל התמיכה ב-overscroll-behavior במאגרי גלילה שלא ניתן לגלול בהם היא מפרט חדש יותר שלא ניתן לזהות את התכונה שלו.

אל תנסו לזהות תכונות של תמיכה בקונטיינרים שלא ניתן לגלול באמצעות @supports (overscroll-behavior: contain) או CSS.supports('overscroll-behavior', 'contain'). כל הדפדפנים המודרניים תומכים בתחביר של המאפיין overscroll-behavior: contain ומחזירים את הערך true, גם אם הם אוכפים אותו רק כשהתוכן חורג מהגבולות.

במקום זאת, התייחסו להכלה של גלילה בקונטיינרים של גלילה שלא ניתנים לגלילה כשיפור הדרגתי (progressive enhancement):

  • בדפדפנים שתומכים ב-overscroll-behavior במאגרי גלילה שלא ניתנים לגלילה, הגלילה של דף הרקע נמנעת לחלוטין גם מעל dialog::backdrop וגם בתוך <dialog> (בין אם התוכן שלו חורג ובין אם לא).
  • בדפדפנים שעדיין לא תומכים ב-overscroll-behavior במאגרי גלילה שלא ניתנים לגלילה, overscroll-behavior: contain ב-dialog עדיין מונע שרשור גלילה בכל פעם שהתוכן של תיבת הדו-שיח עצמה חורג וניתן לגלילה. בינתיים, showModal() עדיין לוכד את מיקוד המקלדת ומסמן את מסמך הרקע inert.
  • מומלץ להסתמך על שיפור הדרגתי (progressive enhancement) במקום על פתרונות עקיפים מדור קודם שמחילים את overflow: hidden או position: fixed על <html> או <body>, כי הוא לא מסיר את סרגל הגלילה הבסיסי, לא גורם לשינויים בפריסה האופקית, לא מקפיץ את מיקום הגלילה בדף ולא משבש רכיבי position: sticky בדף שמתחת.