SVGs are amazing for adaptive dark mode pages

← back to blog

16 December 2025

I built this website with simplicity in mind, trying to keep complexity to a minimum while also keeping space for cool features such as dynamic theme switching according to the device settings. While implementing it, one of the main challenges was allowing the icons (SVGs) to change their colors accordingly.

The idea

A cool feature I stumbled upon is the <style> tag of SVGs, which seems to be supported on all major browser engines. Here is what a dynamic themed rect should look like:

<svg xmlns="http://www.w3.org/2000/svg"
    viewBox="0 0 40 20" width="40" height="20">
    <style>
        @media (prefers-color-scheme: dark) {
            .my-object { fill: #aaa; }
        }
        @media (prefers-color-scheme: light) {
            .my-object { fill: #333; }
        }
    </style>
    <rect class="my-object" width="40" height="20"/>
</svg>

Here’s the same SVG, rendered:

You can try to switch the theme on your phone/laptop to see how the SVG responds; it should immediately change its color to one that matches the background.

I tried applying that to my icons and was happy with the result. For example here’s a flask icon that I made:

The issue

There was, however, one critical issue. Safari (or any browser using the Webkit engine) was the only browser that ignored the <style> tag when the SVG was referenced from an external file.

This is quite sad as it is quite useful to keep the HTML code clean and avoiding redundancy. You can try it by yourself by including an SVG in a HTML page by using <img src="/path/to/dynamic_icon.svg" width="128" height="128"> and then opening it in safari.

The solution

So I ended up applying CSS filters to the SVGs, turning them white when a dark theme was detected. This is quite straightforward, you generate a filter from a website like this one and then apply it to the class of the <img> tags that you will use to include the SVGs:

@media (prefers-color-scheme: dark) {
  .icon {
    filter: brightness(0) saturate(100%) invert(100%) sepia(3%) saturate(335%) hue-rotate(204deg) brightness(112%) contrast(87%);
  }
}
<img src="/path/to/dynamic_icon.svg" class="icon" width="128" height="128">

The only drawback with this method is that as far as I know there is no way to use SVGs that contain multiple colors.

Here you can see my tests on Safari, Chrome and Firefox:

Safari
safari
Chrome
chrome
Firefox
firefox