Encodera

Thanks for reading!

Donate to the site — we work hard for you.

How to prevent page scrolling under a modal dialog

Short answer

While a <dialog> is open, turn off page scrolling with a :has() rule — no JavaScript is needed for that:

<style>
  html:has(dialog[open]) { overflow: hidden; }
</style>
 
<button onclick="box.showModal()">Open the dialog</button>
<dialog id="box">
  <p>The page behind does not scroll now.</p>
  <button onclick="box.close()">Close</button>
</dialog>
<p style="height: 600px;">Long page content…</p>

One line of script opens and closes the dialog, and CSS locks the scrolling: as soon as <dialog> gets the open attribute, the root element gets overflow: hidden.

Scrolling inside the dialog

If the dialog has its own long list, scrolling past its end makes the browser scroll the page underneath. overscroll-behavior stops that:

.modal-body { max-height: 60vh; overflow-y: auto; overscroll-behavior: contain; }

The page jump

When the scrollbar disappears, the page gets wider and the content shifts right. scrollbar-gutter: stable on html reserves room for the bar in advance, and nothing jumps.

Common mistake

overflow: hidden is put only on body, while it is actually the root html element that scrolls — especially if it has a height or its own overflow somewhere. The page keeps scrolling. Set the rule on html, as in the example — or on both elements.

Functions used in this recipe

  • overflow — What to do with content that does not fit into the element.
  • :has() — Matches an element that contains something matching the selector in brackets — the "parent selector".
  • <dialog> — A dialog box; a modal one is opened with `showModal()` and blocks the rest of the page.
  • <body> — The visible part of the page: everything the user sees.

Thanks for reading!

Donate to the site — we work hard for you.