Contact support

We reply by e-mail, usually within two days.

Google reCAPTCHA checks this submission against abuse; data is sent to Google. The script loads only once you open this form.

← All posts

A counter that follows the page into dark mode

A counter is an image on somebody else's page. When that page has a dark mode, the image does not know: it was drawn on the server, long before the visitor's system preference existed as a fact. A white badge on a dark page is the usual result, and it looks like a hole.

Fifteen of the designs here handle it anyway. Not by asking the page, and not with JavaScript — there is none involved. The image switches by itself.

How

SVG is not a picture, it is a document, and a document can carry a stylesheet. So the server draws the design twice, light and dark, puts both into one file, and adds three lines of CSS:

.s4uD{display:none} @media(prefers-color-scheme:dark){.s4uL{display:none}.s4uD{display:inline}}

The browser applies that media query inside the image, even when the image is loaded through a plain <img> tag from another domain. Switch your system to dark and the counter follows — without a reload, without the page around it being involved at all.

What it costs

Both versions are in the file, so the file is about twice the size. Measured on one design: 1,029 bytes normally, 2,041 with the dark twin. That is the honest price and the reason it is not the default: it is requested per embed rather than imposed on everyone.

There is no second request and no second round trip. One file arrives, and the half that is not needed is never painted.

The trap in the middle

Gradients, filters and masks in SVG are referenced by id. Both versions of a design are generated by the same code, so both bring gradients called g1, g2, and so on. Put both into one document and the second definition of an id simply does not apply — the dark version silently renders in the light version's colours.

Nothing errors. The file is valid. It just looks wrong in a way that is easy to blame on the design rather than the assembly.

So before the two halves are joined, every id in the dark version is renamed with a prefix, and every url(#...) that points at one is rewritten to match. It is a small step and skipping it produces a bug that a quick look cannot explain.

When it refuses

If either half is missing, if either fails to produce an <svg> element, or if the two come out byte-identical — which means the design has no dark variant — the light version is returned unchanged. Half an assembled SVG would be worse than no dark mode at all, and a counter that draws is worth more than a counter that is clever.

Advertisement