Black Sheep Code
rss_feed

Adding dark mode to a blog - how to avoid flashes of the wrong theme

Published:

I've added dark mode to this blog.

I followed this fantastic guide from LogRocket. I'm not going to repeat what they've done there, we'll just mention that they're making using of CSS variables, the @media (prefers-color-scheme: dark) query, and the package react-responsive for queries inside of React.

Here's a few additional things that I had to do.

Render conditional images client side.

I'm being a little bit clever with the main blog image on the front page - in light mode I show a sheep during the daytime and in dark mode he's in a dark room illuminated by the laptop screen.

A black sheep typing at a computer

Light mode image

A black sheep typing at a computer

Dark mode image

The server-side-rendered first render isn't aware of what the users preferred color scheme is, and so that image would aways come through as the light mode image.

The solution is to do the conditional check on the client side. We display nothing on first render (the server render) and the second render when we know what the user preference is, we display the image.

This introduces a slight problem of having an image pop of the image suddenly appearing. To mitigate this I use a CSS animation to make it fade in over 100ms.

I later removed this, I found the image fade in jarring. I opted for a simpler solution of displaying both images, and using a CSS media query on preferred theme to determine which one is displayed.

Conditionally use stylesheets

This blog uses highlight.js the plain markdown codeblocks. HighlightJS provides light and dark themes separately - they don't provide user responsive themes.

Using the user preference via react-responsive to determine the theme would have the same issue as the conditional rendering of the image above, the server isn't aware of the user preference, and you'd get a style pop when the page loads and the theme switches.

Fortunately there's a very handy way to conditionally apply CSS. Per this very handy issue thread - I import both themes, conditionally choose the one matching the user's preference with a media="(prefers-color-scheme: dark)" attribute on the link tag.

Other miscellaneous updates

I needed to update my utterances config

I also made updates to react-github-permalink to have it include a user preference responsive theme.



Questions? Comments? Criticisms? Get in the comments! 👇

Spotted an error? Edit this page with Github