Making single color SVG icons work in dark mode

In a project I work on, we had a couple of buttons that consisted of just icons (with visually hidden help text). The QA engineer I worked with, found some of those did not show up in dark mode, which rendered the buttons unusable for users of that mode. Using inline SVGs with currentColor fixed the issue.

What’s dark mode?

Dark mode (similar-ish to high contrast mode) is a setting on platforms, browsers or devices that inverts a user’s colour scheme: from dark elements on a light background to light elements on a dark background.

This setting improves the experience for all sorts of users. For instance, people who work in the evening, those spend a lot of time behind their screens and users with low vision. It also saves energy on some types of screens.

Dark mode is available on the latest macOS and Windows 10, but also in the form of a browser plugin (Dark Background and Light Text add-on for Firefox, Dark Night Mode Chrome extension). In this post I’ll refer to Dark Modes as one thing that generally works the same across different implementations. In reality, there can be inconsistencies, of course. They can be tricky to test remotely, as testing platforms like Browserstack don’t support dark modes for security reasons.

Some dark modes will flip colors on existing websites, turning your white colours black. In our project, we try to make our interface work with that kind of dark mode, as some of our users use these settings and it lets them have a much better experience. This is a relatively cheap accessibility win.

Inline SVGs to the rescue

Let’s assume our site has a light background with black icons. One way to include an SVG icon is to use an <img> tag pointing to the SVG. Here’s an example of a chevron icon:

<img src="chevron-right.svg" alt="" aria-hidden="true" role="presentation" />

(examples on CodePen)

In Windows High Contrast, Dark Background and Light Text and Dark Night Mode, the icon simply did not show. I believe the reason is that Dark Modes generally parse style sheets only, they ignore the contents of markup (including SVG files). In those cases, they will not replace black with white.

If we could only set the color for these SVGs in our stylesheets! Well, currentColor allows for that, and, it turns out, that actually works with Dark Modes:

<svg
  xmlns="http://www.w3.org/2000/svg"
  width="24"
  height="24"
  viewBox="0 0 24 24"
  fill="none"
  stroke="currentColor"
  stroke-width="2"
  stroke-linecap="round"
  stroke-linejoin="round"
> 
  <polyline points="9 18 15 12 9 6" />
</svg>

For those new to currentColor: it resolves to whatever the CSS color is (as set or inherited) of the element the svg is used in. So if a tool updates all colors in the page, the SVGs automagically change colour too. It is also popular because it works great with states like hovers: for icons with text, icon colours will change whenever you change the text colour.

Declaring supported color schemes

After I posted this, Amelia Bellamy-Royds helpfully pointed me at a proposal for declaring color schemes preference. It is proposed to be a property you can set at root level (supported-color-schemes: light || dark) or as a meta tag, so that browsers can be in the know before they start parsing CSS. The property basically lets you tell a browser that your CSS supports dark modes and will not break in them. Safari has experimental support for the property in Technology Preview 71.

The supported-color-schemes property is meant to be used in conjunction with the prefers-color-scheme media query.

Conclusion

So, if you use currentColor for the only (or primary) colour in your SVG icons, they will work better in dark modes. I’ve not done much more research than this, but hope it helps others who try to make their icons work in dark mode. Feedback more than welcome!

Update 25-12-2018: added section about declaring color schemes.

Thanks Šime Vidas, Amelia Bellamy-Royds and Timothy Hatcher for their feedback and suggestions.

Comments, likes & shares (1)

#svg in high contrast mode, currentColor can help. hidde.blog/making-single-…