Hugo Add Customized CSS or Javascript
Recently I switched the static website generator from Hexo to Hugo. The main reason is that Hexo is too slow, cannot generate websites with thousands of pages.
Then I found this: # Who Should Use Hugo?
Hugo is for people building a blog, a company site, a portfolio site, documentation, a single landing page, or a website with thousands of pages.
No pain no gain. To use Hugo smoothly, the first problem is how to add customized css or js to the site.
The bad news is that Hugo is not that friendly to a freshman. I spent hours to read documents and understood how it works. Comparatively, Hexo's plugin system and injector is more friendly to a freshman (maybe I forgot how long to learn it haha :-D).
In this post, we will go through how to add customized css or js to
Hugo sites in Hugoic
way.
If you don't want to understand how it works, just go to
Modify Templates
section would be fine. :-)
Hexo Add Customized css/js
Add Customized css/js in Hexo is easy, just add a new file
custom.js
in the scripts
folder of project
root directory, then the js would be appended to the end of
<head>
:
hexo.extend.injector.register('head_end', () => {
return '<script data-ad-client="ca-pub-xxx" async src="https://pagead2.googlesyndication.com/pagead/js/adsbygoogle.js"></script>';
}, 'default');
Add Customized css/js In Hugoic Way
Simliar to pythonnic
, what's the Hugoic way to inject
customized css/js?
Hugo runs on top of theme templates, so we need to modify the templates to inject css/js. Before that, we should get some understanding of Hugo basics.
Hugo Layouts Lookup Rules With Theme
The first lesson:# Hugo Layouts Lookup Rules With Theme:
In Hugo, layouts can live in either the project’s or the themes' layout folders, and the most specific layout will be chosen. Hugo will interleave the lookups listed below, finding the most specific one either in the project or themes.
Unfortunately, I don't find the priority of project layout and theme layout explicitly. Here is an unofficial explanation: # Customizing a Theme。
Customize the Templates
Based on Hugo layouts lookup rules, we should customize the templates by two steps:
- Copy
/themes/<yourtheme>/layouts/partials/xxx.html
to the project root/layouts/partials/xxx.html
, aka created a new file with the same folder structure of theme folder in the project root - Modify the new file
/layouts/partials/xxx.html
and add css/js code
The main advantages of the solution is the theme can be upgraded independent of the project repo. If we modify the theme files directly, there might be many conflicts when upgrade the theme.
The first time I read the above solution, I don't understand why it works. I spent hours to read documents and found that Hugo has many implicit rules. Here the rule would be the templates in the project layout will overwrite the templates in the theme layout.
layouts/_default/
holds many default templates, while
layouts/partials
holds partial templates:
Partials are smaller, context-aware components in your list and page templates that can be used economically to keep your templating DRY.
# Partial Template Lookup Order:
However, partials are simpler in that Hugo will only check in two places:
- layouts/partials/*<PARTIALNAME>.html
- themes/<THEME>/layouts/partials/*<PARTIALNAME>.html
This allows a theme’s end user to copy a partial’s contents into a file of the same name for further customization.
Modify Templates
Here we take theme PaperMod
as example, copy
/themes/PaperMod/layouts/partials/head.html
to
/layouts/partials/head.html
and append the following code
to the file end:
...
{{ range .Site.Params.customcss }}
<link rel="stylesheet" href="{{ . | absURL }}">
{{- end }}
{{ range .Site.Params.customjs }}
<script type="text/javascript" src="{{ . | absURL }}"></script>
{{- end }}
{{ range $elem := .Site.Params.customjscssraw }}
{{ $elem | safeHTML }}
{{- end }}
To fully understand the code, we need to read # Context
and function usage of range
, absURL
and
safeHTML
in # Introduction to Hugo
Templating.
Why do we need customjscssraw
since we alreadly have
customcss
and customjs
? Because sometimes add
raw html is more flexible: add css integrity property, or add async
keywords to js. This feature is comparable to Hexo injector. See the
examples in the next section.
Add CSS or Js in the
config.yml
The usage is pretty easy, just add the configuration like this (support muliti-line js as well):
params:
...
customcss:
- "css/xx.css"
customjs:
- "js/xx.js"
customjscssraw:
- "<link rel='stylesheet' href='https://cdn.jsdelivr.net/npm/@fortawesome/fontawesome-free@5.15.3/css/all.min.css' integrity='sha256-2H3fkXt6FEmrReK448mDVGKb3WW2ZZw35gI7vqHOE4Y=' crossorigin='anonymous'>"
- >
<script async src='https://www.googletagmanager.com/gtag/js?id=G-XXX'></script>
<script>
window.dataLayer = window.dataLayer || [];
function gtag(){dataLayer.push(arguments);}
gtag('js', new Date());
gtag('config', 'G-XXX');
</script>
Tips: Don't forget to add your css/js files to the
static/
folder if their path are relative.