Skip to main content Accessibility Feedback

The dialog modal ::backdrop, CSS variables, and Safari

I love the native <dialog> element, and I love CSS variables. I make heavy use of both in Kelp.

Last week, I ran into yet another CSS bug around using CSS variables to style the ::backdrop on modal <dialog>’s in Safari on iOS.

The original Kelp CSS for the <dialog> element backdrop looked like this…

dialog {
	--backdrop-opacity: 0.5;
	/* The rest of the variables and styles... */
}

/**
 * Style the backdrop
 */
dialog:modal::backdrop {
	background-color: rgba(0, 0, 0, var(--backdrop-opacity));
}

This makes it really easy to set the ::backdrop opacity using a single CSS variable. You can change it globally like this…

dialog {
	--backdrop-opacity: 0.25;
}

Or just on specific <dialog> elements, like this…

<dialog style="--backdrop-opacity: 0.25">
	<!-- ... -->
</dialog>

This works in every browser… except Safari on iOS!

For some reason, Safari on iOS seems to not associate the ::backdrop with it’s <dialog>. As a result, the --backdrop-opacity variable cannot be found, the rgba() property gets an implicit value of 0, and the background becomes fully transparent.

This is exclusively an iOS issue. It works as expected in Safari on macOS.

The only way to fix it is to either…

  1. Hard-code your styles without a CSS variable.
  2. Apply the CSS variable to the :root, where in the ::backdrop on iOS Safari has access to it.
/**
 * This works
 */
dialog:modal::backdrop {
	background-color: rgba(0, 0, 0, 0.5);
}


/**
 * So does this
 */
:root {
	--backdrop-opacity: 0.5;
}

dialog:modal::backdrop {
	background-color: rgba(0, 0, 0, var(--backdrop-opacity));
}

Either way, you loose the ability to modify the variable in-context of the <dialog> element.