Styling an HTML dialog modal to take the full height of the viewport

I've been experimenting with the HTML dialog element recently, for example in my Prompts.js JavaScript library.

Today I got Claude to build me an experiment to use it for a side panel that would slide in from the right hand side of the screen, looking like this:

The background of a page is dulled. A side panel reaches 80% across the page showing item details - but there's an annoying grey gap below it.

But what's with that gap at the bottom? I want the side panel to take up the full height of the screen.

The CSS looked good to me:

dialog {
    position: fixed;
    margin: 0;
    padding: 0;
    border: none;
    width: 80%;
    height: 100vh;
    top: 0;
    right: 0;
    left: auto;
    background-color: white;
    box-shadow: -5px 0 15px rgba(0, 0, 0, 0.1);
    transform: translateX(100%);
    transition: transform 0.1s cubic-bezier(0.2, 0, 0.38, 0.9);
}

Where was that gap coming from?

I tried poking at Claude, then ChatGPT, and by the time I was screen sharing with Gemini 2.0 Flash and arguing out loud with it about the CSS Natalie overheard and took pity on me and stepped in to help.

Her suspicion was that this had something to do with the <dialog> element. I got Claude 3.7 Sonnet to rewrite the code to use a div instead of a dialog and the mysterious gap vanished, which was a strong hint that she was right.

I was using Firefox. Natalie pointed out that Chrome DevTools display default browser styles for elements, so we switched to that and...

Some thing in the Chrome DevTools. An arrow points to a line from the user agent stylesheet which applies max-height: calc(100% - 6px - 2em) to dialog:-internal-dialog-in-top-layer

Chrome was applying these default styles, including one for max-height:

dialog:-internal-dialog-in-top-layer {
    position: fixed;
    inset-block-start: 0px;
    inset-block-end: 0px;
    max-width: calc(100% - 2em - 6px);
    max-height: calc(100% - 2em - 6px);
    user-select: text;
    visibility: visible;
    overflow: auto;
}

The mysterious gap was entirely explained by that max-height: calc(100% - 2em - 6px); rule.

Adding max-height: inherit to my CSS (or max-height: 100vh) fixed the bug!

Same screen as before but this time the sidebar panel stretches from the top to the bottom of the viewport with no gap.

You can try that out here.

Spelunking through the HTML specification

I was curious if this was expected behavior, so I dug around a bit and found it in the HTML specification here:

15.3.3 Flow content

...

dialog:modal {
  position: fixed;
  overflow: auto;
  inset-block: 0;
  max-width: calc(100% - 6px - 2em);
  max-height: calc(100% - 6px - 2em);
}

The spec lives in GitHub in a 7MB source file which is too large to view through the GitHub web interface, so I ran this:

cd /tmp
git clone git@github.com:whatwg/html
cd html
git blame source | rg 'max-height:' -C 30

It took a while to run:

Blaming lines:  53% (79074/148234)

Which revealed the relevant commit:

075834570 (Tim Nguyen 2023-06-06 21:45:41 -0700 136481) dialog:modal {
075834570 (Tim Nguyen 2023-06-06 21:45:41 -0700 136482)   position: fixed;
075834570 (Tim Nguyen 2023-06-06 21:45:41 -0700 136483)   overflow: auto;
075834570 (Tim Nguyen 2023-06-06 21:45:41 -0700 136484)   inset-block: 0;
075834570 (Tim Nguyen 2023-06-06 21:45:41 -0700 136485)   max-width: calc(100% - 6px - 2em);
075834570 (Tim Nguyen 2023-06-06 21:45:41 -0700 136486)   max-height: calc(100% - 6px - 2em);
075834570 (Tim Nguyen 2023-06-06 21:45:41 -0700 136487) }

075834570 moved that text but didn't introduce it, so I ran the same thing against the parent tree:

git checkout af3ff8382c74f7dc9a98dcdd49a24d96bfc75f26
git blame source | rg '100% - 6px' -C 30

And found this:

979af1532 (Ian Kilpatrick 2020-11-03 10:26:48 -0800 124234)   <ul>
979af1532 (Ian Kilpatrick 2020-11-03 10:26:48 -0800 124235)    <li><span>'position'</span> property to 'fixed'</li>
979af1532 (Ian Kilpatrick 2020-11-03 10:26:48 -0800 124236)    <li><span>'overflow'</span> property to 'auto'</li>
979af1532 (Ian Kilpatrick 2020-11-03 10:26:48 -0800 124237)    <li><span>'inset-block-start'</span> property to '0'</li>
979af1532 (Ian Kilpatrick 2020-11-03 10:26:48 -0800 124238)    <li><span>'inset-block-end'</span> property to '0'</li>
979af1532 (Ian Kilpatrick 2020-11-03 10:26:48 -0800 124239)    <li><span>'max-width'</span> property to 'calc(100% - 6px - 2em)'</li>
979af1532 (Ian Kilpatrick 2020-11-03 10:26:48 -0800 124240)    <li><span>'max-height'</span> property to 'calc(100% - 6px - 2em)'</li>
979af1532 (Ian Kilpatrick 2020-11-03 10:26:48 -0800 124241)   </ul>

Here's 979af1532 with the commit message:

Change modal <dialog>s to be positioned via CSS

Fixes w3c/csswg-drafts#4645. Fixes #5178.

That commit landed in November 2020, and those linked issue threads have all sorts of details about how this change came about.

I also found out today that the HTML Living Standard is very much a living standard - the whatwg/html repo has had 12,318 commits, the most recent of which was less than 24 hours ago.

Created 2025-03-14T16:06:34-07:00 · Edit