skip to content

In CSS, what does the `::backdrop` pseudo-element style, and which elements have one?

level: juniorimportance: nice to knowfreq 30%

answer

  1. the scrim you never had to write
  2. only for top-layer elements
  3. not a node you can query
  4. no content property needed
  5. styled as dialog::backdrop

basics

~20 s

::backdrop is a browser-generated box painted immediately behind an element that is rendering in the top layer — a modal <dialog>, a shown popover, or a fullscreen element — covering the whole viewport. It is where you style the dimming scrim.

solid answer

~40 s

`::backdrop` gives you the scrim behind a top-layer element without adding any markup. The browser generates it for elements in the top layer — a `<dialog>` opened as a modal, an element shown via the HTML `popover` attribute, a fullscreen element — and sizes it to the viewport, painted directly beneath its originating element and above everything else on the page. You target it as `dialog::backdrop`, and typically set `background`, `backdrop-filter`, or an opacity transition on it. It is not a DOM node: you cannot select it from script, attach listeners to it, or put content in it, and it takes no `content` property. User agents already style a modal dialog's backdrop with a translucent dark fill, so your rule usually just overrides `background`.

code

css · 4 lines
css
dialog::backdrop {
  background: rgb(15 15 20 / 0.55);
  backdrop-filter: blur(4px);
}

go deeper

for a junior

Know that dialog::backdrop styles the dimmed area behind a modal, that the browser creates it for you, and that you no longer need a hand-written overlay div for a scrim.

for a middle

Explain that it exists only while the element is in the top layer, that it is generated rather than a DOM node, and which visual properties actually apply to it.

for a senior

Be able to make it animate correctly on open and close, and to say plainly which of the enabling features are recent enough to need a support check or a graceful fallback.

for a principal

Decide whether the design system's overlay primitive is built on dialog plus backdrop or on a legacy scrim element, and own the migration cost and browser-support floor that choice implies.

## What it is Before `::backdrop`, dimming the page behind a modal meant an extra element — a `<div class="overlay">` positioned `fixed; inset: 0` with a translucent background, plus the z-index bookkeeping to keep it under the modal and over everything else. `::backdrop` replaces that pattern with a pseudo-element the browser creates for you. It exists for an element only while that element is rendering in the **top layer**, which happens when a `<dialog>` is opened as a modal, when an element with the HTML `popover` attribute is shown, or when an element is displayed fullscreen. A `<dialog>` that is merely present in the markup, or opened non-modally, has no backdrop. The box is sized to the viewport and painted immediately behind its originating element, so it sits above all ordinary page content without any `z-index` from you. ```css dialog::backdrop { background: rgb(0 0 0 / 0.6); } ``` ## What it is not It is not a DOM node. There is nothing to query, nothing to attach a click handler to, and no way to place text or children inside it. Unlike `::before` and `::after` it does not need — or accept — a `content` property; the browser generates the box unconditionally. Practically, this means "close the dialog when the user clicks the backdrop" is not implemented by listening on the backdrop; a common approach is to listen on the dialog element and compare the click coordinates against its box, which is JavaScript's problem rather than CSS's. ## What you can style It is a real box, so most background and visual properties apply: `background` (colour, gradient, image), `backdrop-filter` for blurring the page behind it, `opacity`, and `transition` / `animation`. Layout properties are mostly pointless because the browser sizes it to the viewport. ```css dialog::backdrop { background: rgb(15 15 20 / 0.55); backdrop-filter: blur(4px); } [popover]::backdrop { background: transparent; } ``` Animating it is the one place with real subtlety. Because the element is added to and removed from the top layer rather than merely changing opacity, a straightforward `transition` on the backdrop has nothing to transition from when it appears, and the element is gone before a fade-out can run. The pieces that make this work are `@starting-style` for the entry value and `transition-behavior: allow-discrete` so discrete properties participate; browsers additionally expose an `overlay` property so the element stays in the top layer for the duration of the exit transition. Support for that combination is more recent than `::backdrop` itself, so verify it against your support floor rather than assuming it. ## The inheritance wrinkle Originally `::backdrop` was specified as inheriting from nothing — it had no parent for the purposes of the cascade — which surprised people whose theme custom properties were defined on `:root` and did not reach it. The specification was later changed so that `::backdrop` inherits from its **originating element**, and current Chromium implements that. If you rely on inherited custom properties inside a backdrop rule, confirm the behaviour in your target browsers; setting the value explicitly on the backdrop rule is the portable choice. ## Where it fits Treat `::backdrop` as the CSS half of the top-layer story: the top layer solves "my overlay must be above everything", and `::backdrop` solves "and everything behind it must be dimmed", both without an extra element and without a single `z-index`. If you are still hand-rolling a scrim div for a modal, that is a sign the component predates the dialog element rather than a requirement of the design.

  • Can you attach a click handler to `::backdrop` to close the dialog?
    No — it is a generated box, not a DOM node, so there is nothing to select or listen on. The usual approach is a listener on the dialog itself that checks whether the click landed outside the dialog's own box, since a click on the backdrop area is reported with the dialog as the target.
  • Why does a plain `transition` on `dialog::backdrop` often fail to fade in or out?
    The element enters and leaves the top layer rather than just changing opacity, so on entry there is no prior value to transition from and on exit the element is removed before the transition runs. `@starting-style` supplies the entry value, `transition-behavior: allow-discrete` lets discrete properties animate, and the `overlay` property keeps it in the top layer while it exits.
  • Does a `<dialog>` that is in the markup but not opened as a modal have a backdrop?
    No. The backdrop exists only while the element renders in the top layer. A dialog opened non-modally stays in normal page flow with no backdrop, and one that is simply present and closed renders nothing at all. Fullscreen elements and shown popovers get one for the same reason a modal dialog does.

saying these in an interview costs you the question

  • Thinks ::backdrop needs a content property like ::before
  • Tries to add a click listener to the backdrop
  • Believes any positioned element can have a backdrop
  • Expects a closed or non-modal dialog to show one
  • Assumes it inherits page custom properties everywhere

context