Skip to content

Dark-mode Responsive SVGs

Posted on:June 28, 2020

SVGs can be made to work with dark mode by using currentcolor. currentcolor allows an SVG to take the color value from its ancestors (usual cascading rules apply). By manipulating the parent’s color attribute, we can effectively make SVGs dark-mode responsive.

Here is the SVG for the header links on this site, as provided by gatsby-remark-autolink-headers:

<svg
  aria-hidden="true"
  focusable="false"
  height="16"
  version="1.1"
  viewBox="0 0 16 16"
  width="16"
>
  <path
    stroke="currentcolor"
    fill-rule="evenodd"
    d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"
  ></path>
</svg>

For gatsby-remark-autolink-headers, this is how I have it set:

// in gatsby-config.js
{
  resolve: "gatsby-remark-autolink-headers",
  options: {
    className: "autolink-link",
    icon: "<svg>...</svg>",
  },
},

className here is used to specify a custom class name to the anchor tag that wraps the SVG, like so:

<a href="#usage" aria-label="usage permalink" class="autolink-link before">
  <svg>...</svg>
</a>

Then, using gatsby-plugin-dark-mode and CSS variables, we can concisely and accurately match the colour of the SVG to that of the text:

body {
  --text: rgba(39, 39, 39, 1);
  color: var(--text);
}
 
body.dark {
  --text: rgba(220, 220, 221, 1);
}
 
.autolink-link {
  color: var(--text);
}

Try it out

See it in action by toggling dark mode on this site and hovering over the header above.