What colour is that iframe?

I have a colleague who has been insisting lately that that the <iframe> element was a mistake and should be deprecated. After recent adventures, I’m more pursuaded than ever (which is to say, not very pursuaded at all, but still, he has a point).

Mixing <iframe>s and support for dark mode creates a real tangle of a web and it’s something we came across recently when we discovered some of our Datawrapper embeds were getting an unexpected off-black background in some browsers.

Screenshot of a chart embedded in a page with a black background. The chart has a slightly off-black background.
There is a slightly off-black background on the chart, surrounded by a pure black. Depending on the quality of your screen, it might be hard to see.

What we want, and were expecting, is for the <iframe> background to be transparent so the embedding page’s background colour can shine through. But after reading through the documentation, some other explanations, and the trials and tribulations of others facing similar challenges, I didn’t feel that much closer to a solution.

It appeared as though the browser was applying a default background colour which we couldn’t control or remove without modifying the embedded document (which we couldn’t do easily since we didn’t control it).

Where is that opaque background coming from?

What it took me too long to figure out is that the default canvas background colour is applied to <iframe> documents (not the <iframe> element, but the page being embedded) by browsers only when there is a colour scheme mismatch. Presumably this is in the spec and I had just failed to understand what I was reading, but the first I actually saw it was burried deep in a comment thread on the W3C CSSWG drafts GitHub repository.

If the color scheme of an iframe differs from embedding document iframe gets an opaque canvas bg appropriate to its color scheme

To understand this better it helps to know1 how browsers determine the color-scheme of a document. It seems to work something like this:

  1. Is there any information about what colour schemes the document supports (meta tag or CSS)? This will likely either be light, dark, or both, or it won’t exist.
  2. In the case of expressed support for a single light or dark — use that scheme.
  3. If support for both light and dark is expressed, check the user’s preference (which defaults to light if there isn’t one) and use that.
  4. If no support is expressed, default to light and use that2.

The browser does this for both the embedded document and the document (or element) in which it is embedded. Once the calculated scheme of each frame is known, we can know the default background colour of the embed’s canvas.

parent iframe default iframe document background
light light transparent
light dark browser’s dark scheme default background colour
dark light browser’s light scheme default background colour
dark dark transparent

There are a lot of combinations to think about and you can see how they all work on this demo page.

Element colour schemes

Another thing I’d failed to appreciate is that it’s possible to define the supported colour schemes on individual elements. So, for example, in a page which only supports a light colour scheme, you could tell the browser that a specific element on that page only supports a dark scheme.

This turned out to be the key to solving our particular problem.

We had a page that only supported a light colour scheme, but has a section with dark styling. Within that darkly styled section we wanted to embed an <iframe> that only supports dark mode.

In this scenario, you end up with an opaque background colour on the embed because the document colour schemes don’t match. Unfortunately, the default dark background colour didn’t match the dark background colour of our darkly styled section.

To fix it, mark the specific section as only supporting a dark colour scheme:

.dark-section {
  color-scheme: dark;

Hey presto, a transparent background!

Demo and testing

To help figure this all out, I created a demo page to have a play around with how browsers behave when embedding documents with different combinations of colour scheme support.

You can have a play yourself and use browser tools to simulate different user colour scheme preferences. But a word of warning: as of early 2023 these browser devtools appear to be a bit buggy and you need to refresh the page each time you switch colour scheme preference to be sure you’re seeing the correct result.

  1. I don’t actually know this is how it works. If you do know how it works — especially if I’ve got it wrong in material ways — I’d love to know about it.
  2. This might be further complicated by silly browser preferences like forced dark mode.