css.ChromaStyles
Syntax
Returns
The css.ChromaStyles function returns a CSS stylesheet for the syntax highlighter as a Resource object. This stylesheet is needed when the noClasses option is false, either as a global default in your project configuration or as an override when using any of the following:
- The
highlightshortcode - The
transform.Highlightfunction - The
transform.HighlightCodeBlockfunction - Highlight options in the info string of a fenced code block in Markdown
Hugo caches the result, so calling the function multiple times with the same options incurs no additional overhead.
Options
The css.ChromaStyles function requires an options map. The targetPath is the only required option.
classDark- (
string) WhenmodeSelectoristrueandmodeisdark, the CSS class name used to scope selectors. Default isdark. classLight- (
string) WhenmodeSelectoristrueandmodeislight, the CSS class name used to scope selectors. Default islight. highlightStyle- (
string) The foreground and background colors for highlighted lines, such as#fff000 bg:#000fff. Defaults to the colors defined by the selectedstyle. lineNumbersInlineStyle- (
string) The foreground and background colors for inline line numbers, such as#fff000 bg:#000fff. Defaults to the colors defined by the selectedstyle. lineNumbersTableStyle- (
string) The foreground and background colors for table line numbers, such as#fff000 bg:#000fff. Defaults to the colors defined by the selectedstyle. mode- (
string) The color mode, eitherlightordark. The specified style must support the given mode. If you omit this option, Hugo uses the style’s default mode. modeSelector- (
bool) Whether to scope CSS selectors under a top-level mode class. For example, alightmode stylesheet scopes selectors under.light, producing.light .chromainstead of.chroma. Set totruewhen generating a paired light/dark stylesheet. Default isfalse. omitClassComments- (
bool) Whether to omit CSS class comment prefixes in the generated stylesheet. Default isfalse. style- (
string) The syntax highlighting style. Defaults to thestylevalue in your project configuration. See syntax highlighting styles for a list of available styles. targetPath- (
string) The target path of the resource, relative to thepublishDir. Required.
Examples
In the first two examples, call the partial template from your base template using the partials.IncludeCached function. Both examples assume this project configuration:
markup:
highlight:
noClasses: false
style: github
[markup]
[markup.highlight]
noClasses = false
style = 'github'
{
"markup": {
"highlight": {
"noClasses": false,
"style": "github"
}
}
}
Single stylesheet
To generate and include a stylesheet using the style value in your project configuration:
{{ $opts := dict "targetPath" "css/highlight.css" }}
{{ with css.ChromaStyles $opts }}
<link rel="stylesheet" href="{{ .RelPermalink }}">
{{ end }}Light and dark stylesheets
To generate and include paired light and dark stylesheets for a style that supports both modes:
{{ $opts := dict
"mode" "light"
"targetPath" "css/highlight-light.css"
}}
{{ with css.ChromaStyles $opts }}
<link rel="stylesheet" href="{{ .RelPermalink }}">
{{ end }}
{{ $opts := dict
"mode" "dark"
"modeSelector" true
"targetPath" "css/highlight-dark.css"
}}
{{ with css.ChromaStyles $opts }}
<link rel="stylesheet" href="{{ .RelPermalink }}">
{{ end }}The light stylesheet is unscoped and acts as the default. The dark stylesheet’s selectors are scoped under the dark class, so its rules take effect only when the root element has that class.
Complete example
This example adds a light/dark/system theme switcher to your site, using the css.Build function to bundle the generated stylesheets into your main CSS file.
- Step 1
- Add this to your project configuration:
markup: highlight: noClasses: false style: github[markup] [markup.highlight] noClasses = false style = 'github'{ "markup": { "highlight": { "noClasses": false, "style": "github" } } } - Step 2
- Create a CSS entry file with
@importstatements for the generated stylesheets, plus light and dark rules for the rest of the page:assets/css/main.css@import "./highlight-light.css"; @import "./highlight-dark.css"; html { background-color: #fff; color: #000; color-scheme: light; } a { color: #00e; } html.dark { background-color: #000; color: #fff; color-scheme: dark; } html.dark a { color: #6af; } - Step 3
- Create a partial template to generate the stylesheets and bundle them with the CSS entry file:layouts/_partials/css.html
{{ $opts := dict "mode" "light" "targetPath" "css/highlight-light.css" }} {{ $highlightLight := css.ChromaStyles $opts }} {{ $opts := dict "mode" "dark" "modeSelector" true "targetPath" "css/highlight-dark.css" }} {{ $highlightDark := css.ChromaStyles $opts }} {{ with resources.Get "css/main.css" }} {{ $opts := dict "importContext" (slice $highlightLight $highlightDark) "minify" (cond hugo.IsDevelopment false true) "sourceMap" (cond hugo.IsDevelopment "linked" "none") }} {{ with . | css.Build $opts }} {{ if hugo.IsDevelopment }} <link rel="stylesheet" href="{{ .RelPermalink }}"> {{ else }} {{ with . | fingerprint }} <link rel="stylesheet" href="{{ .RelPermalink }}" integrity="{{ .Data.Integrity }}" crossorigin="anonymous"> {{ end }} {{ end }} {{ end }} {{ end }}The
importContextoption makes the generated stylesheets available whencss.Buildresolves the@importstatements in the CSS entry file. - Step 4
- Create a JavaScript file to control the theme switcher, persisting manual selections in local storage and following the operating system’s preference when the visitor selects the system option:assets/js/main.js
const root = document.documentElement; const fieldset = document.getElementById('theme-switcher'); const mq = window.matchMedia('(prefers-color-scheme: dark)'); const applyTheme = (theme) => { if (theme === 'dark') { root.classList.add('dark'); } else if (theme === 'light') { root.classList.remove('dark'); } else { root.classList.toggle('dark', mq.matches); } fieldset.querySelector(`input[value="${theme ?? 'system'}"]`).checked = true; }; // Keep class in sync with system preference when no manual override is set. mq.addEventListener('change', () => { if (!localStorage.getItem('theme')) { root.classList.toggle('dark', mq.matches); } }); applyTheme(localStorage.getItem('theme')); fieldset.addEventListener('change', (e) => { const next = e.target.value === 'system' ? null : e.target.value; if (next === null) { localStorage.removeItem('theme'); } else { localStorage.setItem('theme', next); } applyTheme(next); }); - Step 5
- Create a partial template to process the JavaScript:layouts/_partials/js.html
{{ with resources.Get "js/main.js" }} {{ $opts := dict "minify" (cond hugo.IsDevelopment false true) "sourceMap" (cond hugo.IsDevelopment "linked" "none") }} {{ with . | js.Build $opts }} {{ if hugo.IsDevelopment }} <script defer src="{{ .RelPermalink }}"></script> {{ else }} {{ with . | fingerprint }} <script defer src="{{ .RelPermalink }}" integrity="{{ .Data.Integrity }}" crossorigin="anonymous"></script> {{ end }} {{ end }} {{ end }} {{ end }} - Step 6
- Call both partial templates from your base template and add the theme switcher markup. The inline script in the
headelement applies the theme before the first paint, preventing a flash of light-themed content when a dark-theme visitor loads a page:layouts/baseof.html<!DOCTYPE html> <html lang="{{ site.Language.Locale }}"> <head> <meta charset="utf-8"> <meta name="viewport" content="width=device-width, initial-scale=1"> <title>{{ site.Title }}</title> <script> const theme = localStorage.getItem('theme'); document.documentElement.classList.toggle('dark', theme === 'dark' || (!theme && window.matchMedia('(prefers-color-scheme: dark)').matches)); </script> {{ partialCached "css.html" . }} {{ partialCached "js.html" . }} </head> <body> <header> <fieldset id="theme-switcher"> <legend>Color scheme</legend> <label><input type="radio" name="theme" value="light"> Light</label> <label><input type="radio" name="theme" value="dark"> Dark</label> <label><input type="radio" name="theme" value="system"> System</label> </fieldset> </header> <main> {{ block "main" . }}{{ end }} </main> </body> </html> - Step 7
- To verify the setup, add a fenced code block to your home page:content/_index.md
```go func printGreeting(showGreeting bool) { if showGreeting { fmt.Println("Hello, World!") } } ```
