Make Hugo Invert Color for Images when Using a Dark Mode - Build a Theme
August 28, 2021 - 665 words

This post will discuss the display problem of images in light / dark mode, and there are some sample images as examples. You can test their display by manually switch the theme of this site. The switcher is in the upper right corner of the left menu bar, and if you are using a phone you can tap the burger button in the upper left corner to call out the menu bar.

The problem

Some images have black text on a white background, which is harsh when using the dark mode:

A sample image have black text on a white background
◉ Figure. A sample image have black text on a white background

While some images have black text on a transparent background, which is not visible when using the dark mode:

A sample image have black text on a transparent background
◉ Figure. A sample image have black text on a transparent background

Both of these cases need the image to be inverted when the reader selects the dark mode.

How to deal with

The approach is using the CSS filters technique. For example, in the following code, .normal is for the normal color and .inverted is for the inverted color.

1
2
3
4
5
6
7
.normal {
	filter: invert(0%);
}

.inverted {
	filter: invert(100%);
}

We can put the above code into a CSS variable, together with the dark mode switch part. Then we edit render hooks in the Hugo template, one of which is for image processing, just add appropriate style to the image there.

About the dark mode switching function I refer to this article in the practice. Roughly speaking, when the reader switch the site theme to dark mode, the whole <html> container will be added a class to indicate that the page in dark mode now (.classList.add("dark")); and when the reader switch to light mode, this class will be deleted (.classList.remove("dark")). On the CSS’ hand, we assign different values to a same variable depending on whether the container has the dark class. While this variable will be used for HTML elements’ styles. See the code below for details.

The code

Here is the HTML code. Give a class to the whole <html> container:

1
2
3
4
5
<html class="theme-container">
    <body>
        <!--Something…-->
    </body>
</html>

Define the same variable --c-img-filter in two different cases, depending on whether the container has the dark class:

1
2
3
4
5
6
.theme-container{
    --c-img-filter: invert(0%);
}
.theme-container.dark{
    --c-img-filter: invert(100%);
}

Finally let’s deal with the Hugo template:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
<!-- layouts/_default/_markup/render-image.html -->

{{ $url := .Destination | safeURL }}
<figure>
    <img src="{{ $url }}"
        {{ $file_name_array := split $url "." }}
        {{ $file_name_len := len $file_name_array }}
        {{ if eq (index $file_name_array (sub $file_name_len 2)) "i" }}
            style="filter: var(--c-img-filter);"
        {{ end }}
    >
</figure>

We didn’t simply add style="filter: var(--c-img-filter);" to all the images. Instead, we analyze file name first. The effect we achieved is: Invert the color of images named as xxx.i.{png|jpg|gif|jpeg|webp|…} when the reader switch to dark mode, while keep as it is for others. For example:

  • This image is named as lorem.i.jpg, which is black text on a white background for light mode, and white text on a black background for dark mode.

lorem.i.jpg
◉ Figure. lorem.i.jpg


  • This image is named as lorem.i.png, which is black text on a transparent background for light mode, and white text for dark mode.

lorem.i.png
◉ Figure. lorem.i.png


  • This image is named as cat.jpg, its color is normal for both light and dark mode.

cat.jpg
◉ Figure. cat.jpg


See also

  1. No.1: Fix the White Flash on Page Load When Using a Dark Mode on a Static Site - Build a Theme
  2. No.2: Make Hugo Invert Color for Images when Using a Dark Mode - Build a Theme (This one!)