Inline only used CSS styles inside head

I’d like to generate the smallest possible inlined css in each page, and if possible then I’d also like to write the css in the same file as the partials/shortcodes html code.

I imagined achieving it like this:

_default/baseof.html


<html>
<head>
  <meta />
  <meta />
  <title>{{ .Title }}</title>
  {{ block "styles" . }}
  {{ end }}
</head>
<body>
  {{ block "main" . }}{{ end }}
  {{ partial "footer.html" . }}
</body>
</html>

{{ define "styles" }}
{{ partial "inline-styles.html" . }}
{{ end }}

partials/footer.html

{{ $footerStyles := `
    footer { 
      background-color: red;
    }
  ` | safeCSS }} 
{{ .Store.Set "footerStyles" (slice $footerStyles) }}
  
  
<footer>Hello footer</footer>

partials/inline-styles.html

{{ $footerStyles := .Store.Get "footerStyles" }}
{{ $messageStyles := .Page.Store.Get "messageStyles" }}

{{ $styles := slice }}
{{ if $footerStyles }}
  {{ $styles = $styles | append $footerStyles }}
{{ end }}
{{ if $messageStyles }}
  {{ $styles = $styles | append $messageStyles }}
{{ end }}

{{ if gt (len $styles) 0 }}
  {{ $combined := delimit $styles "" }}
  <style>
    {{ $combined | safeCSS }}
  </style>
{{ else }}
  <pre>No styles collected</pre>
{{ end }}

When I develop locally then it kinda works (except for initial load) when I navigate around (guess because of cache), but when I build the project then it shows ‘No styles collected’.
If I just call {{ partial “inline-styles.html” . }} at the bottom after all my partials/shortcodes then it also work, but I want the styles inside the head.

I tried to make a global variable at the top and add styles to that (didn’t work, but maybe I did it wrong), and I’m thinking one potential solution would be to define all the required styles inside the content frontmatter, but I don’t want to do that since it would become messy compared to just automatically detecting it based on which partials/shortcodes appear on the page.

Also okay with using tailwindcss as long as the only the used styles for that particular page are rendered in the head, but think they would be even more complicated to do.

Any suggestions would be much appreciated <3

I’d take a step back from the implementation details and look again at your objective.

A few years ago we went through similar optimizations with AMP pages, where all the CSS is within a style element within the head element, and we were limited to 50 KB. Ultimately we:

  1. Transpiled/bundled a bunch of Sass and CSS into a single file, just like you’d do with most sites
  2. Dumped the contents into head
  3. Post-processed each HTML file after Hugo had built the site.

The post processor read the CSS from head to use with purgecss. It wasn’t particularly fast (though using GNU Parallel helped), but we only needed to run it when deploying the site.

Maintaining CSS in partials looks like a long term maintenance nightmare.

2 Likes

I do think it’s would be quite nice and maintainable to have my html/css(/js) together in 1 file similar to vue, but I agree your approach seems very useful. I’ll try it out in combination with tailwindcss.

Thanks a lot <3

This topic was automatically closed 2 days after the last reply. New replies are no longer allowed.