How to have a 'dark mode' for a hugo site?

This is similar to post: Organisation and Configuration for two static sites in the same folder, but it’s been 3 years since that post, so I’m hoping there’s a better alternative.

Recently I’ve switched from Jekyll to Hugo. On my old site, I figured out a hacky way to have two themes for the static site that was pretty close to what was described in the post above.

However, because the difference between the ‘dark’ theme and the ‘light’ theme is one css file name (theme-light.css vs theme-dark.css), I’m hoping there’s some way to switch between the two that doesn’t involve maintaining two sites (even if that maintenance is just copying or linking the entire tree for the second site.)

Is there a better way to do this today?

You can embed a script in the <head> part of all sites.

<script src={{site.BaseURL | absURL }}switchcss.js ><script>

The script can replace itself with a stylesheet link (via DOM).

<link rel=stylesheet href={{site.BaseURL | absURL }}theme-dark.css >

I like this idea. But I’m unsure how to make the script replace itself with the link. Can you give me one more hint for this?

Stackexchange is a great place for these things:

Some of these answers will do the trick.

And Google has some nice opinions about dark themes here:

1 Like

asking auntie Google :wink:
found this

use the VanillaJS version.

1 Like

Thanks! I guess I wasn’t using the right keywords in my searches.

Even when using the VanillaJS version, I’m seeing the flash of unstyled content mentioned before the javascript can load the styles. I also noticed the dates for those solutions are a bit dated.

I was able to cut down the FOUC to a quick blink of a blank white screen (rather than a slower flash of unstyled content) with Jeff’s solution in the the link below (it uses css to hide with 0 opacity), but I was really hoping not to even have that. – But that solution is much better than what I had, so I can live with it, if that’s not the case.

Thanks again for your help!

Is the script on the first place in <head>?

It was the first thing after the meta tags:

<!DOCTYPE html>
<html lang="en">
  <meta charset="utf-8">
  <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
  <meta name="generator" content="Hugo 0.55.6" />

  <style>html{visibility: hidden;opacity:0;}</style>

    var css_title = 'light'
    var link = document.createElement( "link" );
    link.href = "\/\/localhost:1313\/css/colors-" + css_title + '.css';
    link.type = "text/css";
    link.rel = "stylesheet"; = "screen,print";

    document.getElementsByTagName( "head" )[0].appendChild( link );


(the style tag for hiding the HTML was added later.)

For reference, the relevant partial looks like this:

A little late to the party, but I have implemented night mode switch on my Hugo website without light flash! You can see a live implementation of this in the following tutorial: Add Dark Mode to Hugo. Basically, you need to inline all the code inside one partial and it works flowlessly.