What does it mean for an element to render in the browser's top layer — as a `<dialog>` opened with `showModal()` does — and how does that change z-index, clipping, and its containing block?
answer
- a layer painted above the whole document
- z-index cannot reach into it
- clipping and transformed ancestors stop mattering
- ordering is by when it opened
- comes with ::backdrop
basics
~20 sThe top layer is a viewport-sized painting layer above the whole document. An element promoted into it paints over all page content whatever their z-index values, is not clipped by ancestor overflow, and is positioned against the viewport rather than a transformed ancestor.
solid answer
~50 sThe top layer is a rendering layer the browser paints after — and above — the entire document, so it sidesteps the ordinary rules instead of competing inside them. An element enters it when a `<dialog>` is opened as a modal, when an element with the HTML `popover` attribute is shown, or when something goes fullscreen. Once there, no `z-index` anywhere in the page can outrank it, an ancestor's `overflow: hidden` no longer clips it, and its containing block is the viewport, so a transformed ancestor cannot trap it. Its DOM position is unchanged, so it still inherits styles and stays where it is for the accessibility tree and focus order. Ordering within the top layer is by promotion order — the most recently opened element sits on top — not by `z-index`. Each top-layer element can also style a `::backdrop` behind itself.
code
css · 10 linesdialog:modal {
max-inline-size: min(32rem, 90vw);
max-block-size: 80vh;
border: 0;
padding: 1.5rem;
}
dialog::backdrop {
background: rgb(0 0 0 / 0.6);
}go deeper
Know that a modal <dialog> is drawn above the whole page automatically and comes with a ::backdrop you can style, so you do not need z-index tricks for it.
Explain the four things promotion changes — painting above the document, no ancestor clipping, viewport containing block, a backdrop — and that ordering inside the layer follows promotion order.
Argue when the top layer replaces a portal-and-z-index overlay system in a real product, and name what it forces on you: modality behaviour, all-or-nothing painting, and a support floor for popover.
Decide the product-wide overlay primitive: which layers move to the top layer, which must stay interleaved with page content, and what browser-support floor that commits the organisation to.
## The idea Everything in a normal page competes for paint order inside one tree of stacking contexts, and `z-index` only ranks siblings within the same context. That is the root cause of the escalating-`z-index` wars in large apps: a deeply nested overlay can be given any number at all and still lose to something in a different branch. The **top layer** removes the overlay from that competition entirely. It is a viewport-sized layer that the browser paints after the whole document, so anything in it is above everything else by construction. ## How an element gets there Three mechanisms promote an element to the top layer: - a `<dialog>` opened as a modal (`showModal()`); a dialog opened non-modally with `show()` stays in the page and behaves like any other positioned element; - an element with the HTML `popover` attribute while it is shown; - an element in fullscreen. The markup side of `<dialog>` and `popover` belongs to HTML; what matters for CSS is that promotion changes layout and painting in four ways. **Painting.** Top-layer content is painted above all page content. `z-index: 2147483647` on a header does not put it over a modal dialog. **Clipping.** Ancestor `overflow: hidden` and `contain: paint` no longer clip it, because it is no longer painted inside that subtree. **Containing block.** Its containing block is the viewport (the initial containing block), so the classic "transformed ancestor traps my fixed overlay" bug does not apply. This is the property that makes the top layer a genuine fix rather than a bigger hammer. **Backdrop.** The element gets a `::backdrop` pseudo-element painted immediately behind it and covering the viewport, which you style for the scrim. ## What does *not* change Promotion is a rendering concern, not a DOM move. The element stays exactly where it is in the document, so inheritance still flows from its DOM parent, selectors that depend on ancestors still match, and its place in the accessibility tree and source order is unchanged. Inherited properties from an ancestor with `color` or a custom property still reach it. Within the top layer, ordering is by promotion order: open A, then B, and B paints above A. `z-index` still works *inside* each top-layer element for its own descendants, but you cannot use it to reorder two top-layer elements against each other. Close and reopen A and it goes to the top. ```css dialog::backdrop { background: rgb(0 0 0 / 0.6); } dialog:modal { max-inline-size: 32rem; border: 0; } ``` The `:modal` pseudo-class matches an element that is modal — a dialog opened with `showModal()`, or a fullscreen element — which lets you style the modal and non-modal cases of the same component differently. For popovers, `:popover-open` matches while the popover is shown. ## Layout inside the dialog A modal dialog is centred by the user-agent stylesheet using auto margins against the viewport, which is why an empty `<dialog>` already appears centred with no CSS from you. If you want full control, set your own `inset` values; because the containing block is the viewport, they behave like fixed positioning. Sizing wants `max-inline-size` / `max-block-size` with viewport units so tall content scrolls inside the dialog instead of running off-screen. ## When you still would not use it The top layer's whole point is being above everything, which is wrong for overlays that must interleave with page content, or for a component that needs several simultaneous layers whose relative order you control. Modality also brings behaviour beyond CSS — focus containment and inertness of the rest of the page for a modal dialog — which is a feature for dialogs and a nuisance for a lightweight tooltip. Non-modal popovers exist for exactly that middle ground. ## Support `<dialog>` with its top-layer behaviour and `::backdrop` is supported across current browsers; the `popover` attribute is newer and shipped across the major engines during 2023–2024, so check your support floor before relying on it as the only path. Feature detection for the CSS half can use `@supports selector(:popover-open)`.
- Two elements are in the top layer at once. How do you control which one is on top?By the order you open them: the most recently promoted element paints above earlier ones, and `z-index` cannot reorder them. If a second dialog must sit above an existing one, open it after; if an earlier one must come forward, close and reopen it. Inside each element, `z-index` still orders its own descendants normally.
- Does an element in the top layer stop inheriting from its DOM ancestors?No. Promotion changes painting and the containing block, not the element's position in the document, so inheritance, ancestor-dependent selectors, and the accessibility tree are unaffected. A custom property or `color` set on a wrapper still reaches it. Historically the exception was `::backdrop`, whose inheritance rules were defined separately.
- When is a root-level overlay container still preferable to the top layer?When the overlay must sit above some content but below other chrome, when several overlays need an order you control explicitly, or when you need lightweight non-modal layers and cannot use the popover attribute across your support floor. The top layer is deliberately all-or-nothing about painting above everything.
saying these in an interview costs you the question
- Thinks a high enough z-index can beat a modal dialog
- Believes the element is moved in the DOM when promoted
- Assumes ::backdrop is a real child element
- Expects z-index to reorder two open dialogs
- Says a non-modal dialog.show() also uses the top layer