Adding a Dark Mode to Codex Hugo Theme

For this site I’m using Hugo with the Codex theme. In the last few days I’ve been familiarizing myself with how Hugo and Codex works. I hadn’t interacted with them since their install and initial setup.

A Dark Theme is Needed#

We all know that a light theme can attract bugs or scare away a geek because it remembers him too much of the sun. There all sort of disadvantages on having only a light theme on your website.

I like Codex because is minimal and elegant, but it lacks a dark theme.

Since I had few days of free time and wanted to work a bit on my blog, I decided to add one.

Disclaimer: I’m not a professional web developer and I haven’t used JavaScript in years so there is probably a better and more elegant way to achieve this.

Solution#

This site is simple and should remain like this. I don’t plan to implement features like comments or add any other JS dependency.

I wanted a quick and dirty way to change theme.

First, I added a new entry for the navigation bar in the hugo-theme-codex/layouts/partials/nav.html file:

1<li>
2    <p id="theme-button" onclick="changeColorTheme()">☼</p>
3</li>

I decided to use the localStorage on the client side to save the theme chosen by the user.

I added a new Javascript file to the project that sets the value for the theme key in the client localStorage and implements the function for switching the theme when the specific navigation entry is pressed:

 1function changeColorTheme() {
 2    const currentTheme = localStorage.getItem('theme');
 3    const newTheme = currentTheme === 'light' ? 'dark' : 'light';
 4
 5    localStorage.setItem('theme', newTheme);
 6
 7    if (newTheme === "dark") {
 8        document.body.classList.add("dark-mode");
 9    } else if (newTheme === 'light') {
10        document.body.classList.remove("dark-mode");
11    }
12}
13
14const theme = localStorage.getItem('theme');
15if (theme === 'dark') {
16    document.body.classList.add("dark-mode");
17} else {
18    localStorage.setItem('theme', 'light');
19}

Lastly, I defined the following properties in the hugo-theme-codex/assets/scss/custom.scss file:

 1:root {
 2    --color-primary: #111;
 3    --color-secondary: #9b9b9b;
 4    --color-secondary-light: #f7f7f7;
 5    --color-secondary-dark: #717171;
 6    --color-background: #fff;
 7    --color-backgroung-light: #181818;
 8    --color-table-border: #eeeeee;
 9    --color-links: blue;
10    --color-codeblock: #eeeeee;
11    --color-toc-active: #333333;
12}
13
14.dark-mode {
15    --color-primary: #fff;
16    --color-secondary: #9b9b9b;
17    --color-secondary-light: #f7f7f7;
18    --color-secondary-dark: #717171;
19    --color-background: #000;
20    --color-backgroung-light: #181818;
21    --color-table-border: #eeeeee;
22    --color-links: red;
23    --color-codeblock: #242424;
24    --color-toc-active: #eeeeee;
25}

The :root properties defines the default light theme colors, while the .dark-mode class overrides these colors when dark mode is activated.

The Truth#

The truth is that the above steps were not the only ones necessary to implement the dark theme.

Social Icons

I hardcoded the SVG code of the social icons directly in the HTML of the page. Changing the icon used based on the theme with JS didn’t work on mobile phones, so I embedded the SVG in the code and set an ID for each one.

Example for the Github icon:

1<a class="social-icons__link" title="github-icon" href="https://github.com/d3af90d" target="_blank" rel="me noopener">
2    <svg id="github-icon" class="social-icons__icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="#000000" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="feather feather-github">
3        <path d="M9 19c-5 1.5-5-2.5-7-3m14 6v-3.87a3.37 3.37 0 0 0-.94-2.61c3.14-.35 6.44-1.54 6.44-7A5.44 5.44 0 0 0 20 4.77 5.07 5.07 0 0 0 19.91 1S18.73.65 16 2.48a13.38 13.38 0 0 0-7 0C6.27.65 5.09 1 5.09 1A5.07 5.07 0 0 0 5 4.77a5.44 5.44 0 0 0-1.5 3.78c0 5.42 3.3 6.61 6.44 7A3.37 3.37 0 0 0 9 18.13V22" /></svg>
4</a>

Notice the github-icon ID. I set the following snippet for it in the CSS file:

1#github-icon {
2    stroke: var(--color-primary);
3}

I decided to assign a different ID to each icon (and not a single class for all) because some needs a change in the stroke property and other in the fill property. Managing them individually is better for my use case.

I also removed the cute animation used when the navigation bar appears in the mobile version of the site. That animation affected how the site transitioned from light to dark colors and I didn’t like it, so I removed it completely.

SCSS File

I had to override the CSS properties of many elements with a variable used by the theme because many color values were hardcoded. Here the full custom.scss file I have right now.

Next Steps#

  • The colors I’m using in dark mode are temporary. A black background with white text is not pleasant to the eyes at night when the screen is the only light. I need to find better colors.
  • This site supports code highlighting but it breaks in dark mode. I decided not to use it for now, but I need to override the right properties in the CSS so the highlighting appears beautiful both in light and dark mode.
  • I want to check what specific funcionalities Codex has and what JS libraries it uses so I can remove what is not needed. For example, I don’t need Google Analytics or Disquis (I don’t even know what that is 🙈) support on my site.
  • This site’s scroollbar is cute when using firefox but ugly on Brave. I though it was a browser thing but then a friend of mine made me notice that its scrollbar was cute even on Brave. I’ll check how to change its appearance in the future.

When I finished with all of this, maybe I should fork the project and publish it on Github 🤷🏻‍♂️