Docs
Styles
Hinode uses Sass files to take advantage of variables, maps, and functions to generate the cascading style sheets of the website. By utilizing Hugo Modules , Bootstrap’s source Sass file are automatically ingested and kept up to date.
Build pipeline
Note
Hinode has added support for the Dart Sass transpiler in release v0.20.0 . The libsass transpiler has been deprecated in favor of Dart Sass , but is still widely used. Hinode uses the Dart Sass transpiler by default. Review the Build Configuration on how to change the transpiler being used.
Hinode uses Hugo modules and mounted folders to create a flexible virtual file system that is automatically kept up to date. Review the Overview for a detailed explanation. The build pipeline of the stylesheet consists of six steps.
-
Initialize the Sass variables
Hugo v0.109.0 introduced a convenient way to initialize Sass variables from your templates . Hinode initializes several variables in the file
layouts/_partials/head/stylesheet.html. For example, the primary theme color is available as$primary. -
Define the Sass entrypoint
The main entrypoint for the Sass files is defined in
assets/scss/app.scss. It supports Hugo templating. For example, the snippet below conditionally imports font face definitions when using a local font path.{{ if (not (hasPrefix (lower site.Params.style.themeFontPath) "http")) }} @import "theme/fonts.scss"; {{ end }} -
Import the Sass files of core modules
Hinode automatically adds the content of each core module’s Sass entrypoint to a virtual copy of the
assets/scss/app.scssfile, unless they are referenced in the ExcludeSCSS Setting . Hinode expects a fileassets/scss/{MODULE NAME}.scssfor each core module. The referenced files are usually placed inassets/scss/modules/{MODULE NAME}/. -
Override and expand the Sass configuration
The import order of the source files defines which variables and functions to use. In Sass, the first definition of a variable or function takes precedence. For example, to override the setting for the variable
$primary, it needs to be defined prior to Bootstrap’s definition in_variables.scss. -
Transpile the Sass files
The partial
partials/head/stylesheet.htmlreads the application entrypoint, configures thenode_modulesfolder as import path, and transpiles the stylesheet into a single filemain.css. In production mode, the output is minified and linked to with a fingerprint . -
Link to the stylesheet in the base layout
Hinode’s base layout
layouts/_default/baseof.htmlimports the generated stylesheet in the header section of the webpage via the partiallayouts/_partials/head/head.html.
-
Initialize the Sass variables
Hugo v0.109.0 introduced a convenient way to initialize Sass variables from your templates . Hinode initializes several variables in the file
layouts/_partials/head/stylesheet.html. For example, the primary theme color is available as$primary. -
Define the Sass entrypoint
The main entrypoint for the Sass files is defined in
assets/scss/app-dart.scss. It supports Hugo templating. -
Import the Sass files of core modules
Hinode automatically adds the content of each core module’s Sass entrypoint to a virtual copy of the
assets/scss/app-dart.scssfile, unless they are referenced in the ExcludeSCSS Setting . Hinode expects a fileassets/scss/{MODULE NAME}.scssfor each core module. The referenced files are usually placed inassets/scss/modules/{MODULE NAME}/. -
Override and expand the Sass configuration
For backwards compatibility, the various Sass files still use
@importstatements. In this setup, the first definition of a variable or function takes precedence. For example, to override the setting for the variable$primary, it needs to be defined prior to Bootstrap’s definition in_variables.scss. -
Transpile the Sass files
The partial
partials/head/stylesheet.htmlreads the application entrypoint, configures thenode_modulesfolder as import path, and transpiles the stylesheet into a single filemain.css. In production mode, the output is minified and linked to with a fingerprint . -
Link to the stylesheet in the base layout
Hinode’s base layout
layouts/_default/baseof.htmlimports the generated stylesheet in the header section of the webpage via the partiallayouts/_partials/head/head.html.
Stylesheet purging
Hinode trims the generated main.css in production with
PostCSS
. The pipeline is defined in config/postcss.config.js and runs three plugins in order:
-
PurgeCSS
removes every style rule whose class, tag, or id does not appear in
hugo_stats.json— the inventory of elements Hugo actually emitted, generated by the[build.buildStats]setting inhugo.toml. -
Autoprefixer
adds vendor prefixes for the browsers declared in the
browserslistsection ofpackage.json. - cssnano (default preset) compresses the result.
Purging is controlled by the purge setting in the [style] section of params.toml. It is enabled by default since release
v3.6.0
. Purging runs in production builds only: the development server always serves the unpurged stylesheet, so every class is available while you iterate. In production, the purge runs as a post-processing step after all pages have rendered, so hugo_stats.json is complete when PurgeCSS reads it. As a result, the file is a build artifact — add it to .gitignore instead of committing it.
If purge is enabled but the site has no config/postcss.config.js, Hinode logs a warning and serves the unpurged stylesheet. A PostCSS configuration that is present but broken (a syntax error, or missing npm packages such as @fullhuman/postcss-purgecss) instead fails the production build: the error surfaces at post-processing time, outside the scope of Hinode’s configuration guards, with the PostCSS error printed to the build log.
Safelisting dynamic classes
PurgeCSS only sees classes that Hugo writes into the markup. Classes added at runtime by JavaScript — Bootstrap state classes such as show or collapsing, or classes injected by third-party scripts such as cookie-consent banners — must be declared in the safelist section of config/postcss.config.js. Hinode’s default configuration safelists the classes used by its core modules; extend it with the patterns of any additional scripts your site loads, and visually verify the affected components on a production build.
Migrating an existing site
Sites created before release
v3.6.0
typically pinned purge = false or committed hugo_stats.json. To adopt the current pipeline:
- Remove any
purgeoverride fromparams.tomlto inherit the new default, or set it tofalseexplicitly to opt out. - Replace
config/postcss.config.jswith the current Hinode baseline (PurgeCSS → Autoprefixer → cssnano) and re-apply any site-specific safelist entries. - Add a
browserslistsection topackage.json(Hinode uses Bootstrap’s supported browsers) and drop thecssnano-preset-advanceddependency if present — the pipeline uses cssnano’s default preset. - Delete
hugo_stats.jsonfrom the repository (git rm --cached hugo_stats.json) and add it to.gitignore. - Run a production build and visually inspect key pages; safelist any dynamically injected classes that were stripped.
Example
The below Sass file defines a skeleton configuration for the main entrypoint. The full configuration is defined in assets/scss/app.scss (libsass) and assets/scss/app-dart.scss (dartsass) respectively.
// 1) Define template variables (linking to Hugo config)
@import "hugo:vars";
// 2) Include default variable overrides
@import "common/variables.scss";
// 3) Import Bootstrap configuration (mounted by core Bootstrap module)
@import "bootstrap.scss";
// 4) Import Hinode theme styles
@import "components/blockquote.scss";
// 5) Import custom theme fonts and styles
@import "theme/fonts.scss";
@import "theme/theme.scss";
// 6) Import Bootstrap utilities API (mounted by core Bootstrap module)
@import "modules/bootstrap/utilities/api";
// 7) Import additional modules
// Process stylesheet entrypoints for each configured module (w/o excludeSCSS)// 1) Define template variables (linking to Hugo config)
@use "hugo:vars" as
// 2) Include default variable overrides
@import "common/variables-dart.scss";
// 3) Import Bootstrap configuration (mounted by core Bootstrap module)
@import "bootstrap-dart.scss";
// 4) Import Hinode theme styles
@import "components/blockquote.scss";
// 5) Import custom theme fonts and styles
@if h.$import-fonts {
@include meta.load-css(theme/fonts);
}
@import "theme/theme.scss";
// 6) Import Bootstrap utilities API (mounted by core Bootstrap module)
@import "modules/bootstrap/utilities/api";
// 7) Import additional modules
// Process stylesheet entrypoints for each configured module (w/o excludeSCSS)Optional module files
Hinode processes the Sass files that are part of an optional module one at a time. The entrypoint of each module is expected to be found in assets/scss/{MODULE NAME}.scss. The transpiled output is included on a page-by-page basis.