Different syntax highlighting colors for light and dark mode in a Hugo website

Out of the box, Hugo supports a single color scheme for code syntax highlighting, which is enough for most cases. Thankfully, there is also a solution for those who want to have multiple color schemes and be able to change them without rebuilding the entire website.

When Hugo renders an HTML code block during the build time, it uses inline styles to set the color of the element. You can change this behavior to use class names instead by adding the following setting to your configuration file:

# hugo.yaml

markup:
  highlight:
    noClasses: false # use classes instead of inline styles

If you rebuild the website after changing the noClasses setting, you will find that all colors of code blocks are gone. It’s because the elements inside code blocks are using class names that aren’t defined in any stylesheet included in the website.

To fix it, you can create a new stylesheet from scratch or use Hugo to export one of the existing stylesheets and then include it on your website manually.

You can see all the available built-in styles on this website.

Let’s export the GitHub stylesheet and include it in the layout template to bring the colors back.

Exporting a stylesheet is easy with the following Hugo command:

$ hugo gen chromastyles --style=github > static/css/syntax.css

Link the exported stylesheet in the layout template:

<link rel="stylesheet" type="text/css" href="/css/syntax.css" />

Hit the refresh button and see the colors come back.

Let’s export another style to be used in dark mode:

$ hugo gen chromastyles --style=github-dark > static/css/syntax-dark.css

Now we have two different stylesheets that we can use depending on whether the light or dark mode is on.

Including syntax styles using SCSS

If you use CSS/SCSS to define extra styles for your website, please continue reading. Otherwise, jump to the next section where I describe how to include custom syntax highlighting styles using the partial command.

Please note that this method will only work with SCSS and not CSS files. The @import rule in CSS can’t be used inside a selector, which makes it impossible to conditionally apply imported styles to a specific element. This limitation can be overcome using SCSS. The SCSS @import rule inlines the content of a file during the build process, allowing for flexible placement within the document. This is unlike the CSS @import rule, which must be used at the beginning of a file.

No worries if you use CSS, because Hugo supports SCSS to CSS transformation out of the box. It is very easy to set it up. Learn more about it here.

I assume that you differentiate between light and dark mode by using a data attribute on the HTML element. There are other ways to do this, but the concept is still the same. Adjust the code to meet your needs.

// static/css/main.scss

html[data-theme=light] {
  @import "syntax-light";
}

html[data-theme=dark] {
  @import "syntax-dark";
}

Refresh your website and try switching between light and dark modes. You should see different styles applied to code elements.

Including syntax styles using the readFile command

Another way of including the syntax stylesheets is using the readFile. This Hugo command reads a file and inserts the content of the file at the location where the command was used.

You can add an inline style to the head section of your website, and then insert each syntax style into the appropriate selector for light or dark mode.

However, there is one downside to this approach. The resulting stylesheet will use the CSS nesting, which doesn’t work on all browsers. According to Can I use…, the CSS nesting feature is supported by 81% of global Internet users.

Wasn’t CSS nesting used in the previous example? Yes, it was. However, we used SCSS, which takes care of transforming nested selectors into a single complex selector, a combination of multiple selectors connected by a descendant combinator, which has been supported by web browsers since 1996.

I use the first method myself and would recommend it to you as well.

However, if you still want to proceed with the second method, the code below shows how to do it:

<!-- layouts/_default/baseof.html -->

<style>
    html[data-theme=light] {
        {{ readFile "static/css/github.css" | safeCSS }}
    }
    
    html[data-theme=dark] {
        {{ readFile "static/css/github-dark.css" | safeCSS }}
    }
</style>
...

Place it inside the head tag in the layout template.

What’s next?

Now that you know how to extract and alter the stylesheet used in Hugo to render code blocks, you can use it for a variety of purposes.

You can make your blog adjust its code highlighting styles when the light or dark mode is changed.

You can also make a code preview component that allows users to choose from a variety of syntax highlighting themes.

You can import a code style that doesn’t exist in Hugo, or you can create your own style to match the style of your website.