Build a Hugo website | Hugo Elliott

Build a Hugo website

Hugo Elliott

| website | hugo | Est reading time: 8 mins

Logo by Hugo at Hugo

How to make a static website and simple homepage with Hugo

1. Prerequisites and notes

I assume you

Some notes

  • I am creating a new Hugo theme to hold the web sites functionality and styles
  • I use Bulma for the CSS framework
  • A basic knowledge of HTML, CSS and Hugo is a nice to have, but not a must have, and
  • An ellipsis (or 3 dots) such as ‘…’ indicates there is something else I’ve not copied in for brevity

2. Create a new site and theme

To generate a new site, open your terminal, navigate to your project folder and run

hugo new site new-site

This creates a the framework for a ‘Hugo’ website on your computer

Navigate into this directory using the cd command

cd new-site

We’re going to create the new page templates and styling in a new theme. This makes it easier if (in the future) you wish to change to a new template with different functionality

hugo new theme new-theme

where new-site and new-theme are the names of your new website and theme

Open new-site/config.toml and add

theme = “new-theme”

In your terminal run

hugo server

Hugo has an inbuilt server so that you can see your website as it’s being built. This command starts that server.

If you follow the link in your terminal (normally http://localhost:1313/) your browser will open, and your website will be being served… but you have not created any pages yet, we’ll create them below.

3. Define the layout for the Home Page

Open and edit [project name]/theme/[theme name]/layouts/_defaults/index.html adding

<!DOCTYPE html>
<html lang="{{ .Site.LanguageCode }}"></html>
    {{- partial "head.html" . -}}
    <body class="site">
    {{- partial "header.html" . -}}
    <main class="site-content">
        {{- block "main" . }}{{- end }}
    {{- partial "footer.html" . -}}

Aside from setting out the framework, this code

  1. Links the site’s language code to the setting in the config.toml file,
  2. Adds the classes site and site-content to the body and main divs respectively.

The site and site-content classes are used to make a sticky footer for which I use Philip Walton’s solution.

Please note my use of shortened path names

From now on unless specifically stated, all path names will be shortened

  • from [project name]/theme/[theme name]/[folder name]/[file name]
  • to [folder name]/[file name]

i.e. we’ll be working within the theme.

4. Define the Page Head

The Mozilla Developer Network has a good explanation of what should go in the ‘head’ of a HTML document.

Open and edit layouts/partials/head.html adding

    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1, viewport-fit=cover">
    <title>{{ if not .IsHome }}{{ with .Title }}{{ . }} | {{ end }}{{ end }}{{ .Site.Title }}</title>
    <meta name="description" content="{{ with .Description }}{{ . }}{{ else }}{{ with .Summary }}{{ . }}{{ else }}{{ .Site.Params.description }}{{end }}{{ end }}">
    <link rel="canonical" href="{{ .Permalink }}" />

    <!-- Social Media Sharing -->
    {{ template "_internal/opengraph.html" . }}
    {{ template "_internal/twitter_cards.html" . }}

    <!-- CSS -->
    <link rel="stylesheet" href="{{ absURL `css/bulma.min.css` }}">
    <link rel="stylesheet" href="{{ absURL `css/main.css` }}">

    <!-- Google Fonts -->
    <!-- Place holder for Google Fonts -->

    <!-- Google Tag Manager -->
    {{ if not (in (string .Site.BaseURL) "localhost") }}
    <!-- Place holder for Google Tag Manager -->
    {{ end }}
    <!-- End Google Tag Manager -->

Some notes on code the above, it starts by defining the character set (UTF-8), and then adds

  • support for responsive pages on mobile devices,
  • title for each page, if no title is defined then we add the site’s title,
  • description for each page, if there is no description we add the site’s descrption,
  • canonical URL support,
  • support for social sharing, we’ll discuss this later,
  • links to our CSS files discussed below,
  • and placeholders for Google Fonts and Tag Manager.

5. Add Static CSS and Javascript Files

I use the Bulma CSS framework, you could just as easily use Bootstrap or an alternative. If you do [use an alternative] you will need to make changes to the HTML in this blog.

I prefer to save the CSS and Javascript files locally.

Create and edit static/css/bulma.min.css.

  • Go to Bulma’s HTML starter template,
  • copy the url of the CDN link to Bulma,
  • at the time of writing it was version 0.8.2,
  • copy and paste the url into your browser and you’ll see a page of minified code,
  • copy and paste this minified code into the file static/css/bulma.min.css, and then
  • save and close the file.

Create and edit static/css/main.css adding

/* Sticky Footer - */

.site {
    display: flex;
    min-height: 100vh;
    flex-direction: column;
.site-content {
    flex: 1;

This is the code for Philip Walton’s Sticky Footer solution referred to above.

Please note I’ve copied in (and commented out) the link to relevant page, this is just for my future reference. You may see other links like this in my code base.

Save and close the file.

We’ve already added links

<!-- CSS -->
<link rel="stylesheet" href="{{ absURL `css/bulma.min.css` }}">
<link rel="stylesheet" href="{{ absURL `css/main.css` }}">

to bulma.min.css and main.css files in the head.html file, so Hugo should be reference these files.

We now need either Javascript or Jquery to make the Bulma navbar work, specifically to toggle the navbar hamburger on and off depending on screen width. I will use Jquery.

Create and edit static/js/main.js adding

$(document).ready(function() {
    // Check for click events on the navbar burger icon
    $(".navbar-burger").click(function() {
    // Toggle the "is-active" class on both the "navbar-burger" and the "navbar-menu"

Save and close the file.

I need to link the static/js/main.js file into our main template structure.

Open and edit layouts/partials/footer.html adding

<footer class="footer">
    <!-- Javascript -->
    <!-- Fontawesome -->
    <script src=""  crossorigin="anonymous"></script>
    <!-- jQuery -->
    <script src=""></script>
    <!-- Custom javascript -->
    <script src="{{ absURL `js/main.js` }}"></script>

I’ve added

  • A link to Fontawesome (because Bulma uses Fontawesome icons),
  • A CDN link to JQuery version 3.4.1, and
  • A link to our main.js file which contains the code to run the hamburger.

6. Create the Header

Open and edit layouts/partials/header.html adding

    <nav class="navbar" role="navigation" aria-label="main navigation">
        <div class="container">
            <div class="navbar-brand">
                <a class="navbar-item" href="{{ `` | absURL }}">
                    <div class="p-05">
                        <!-- Placeholder for Logo or Image -->
                    <h1 class="title is-size-4"><strong>{{ .Site.Params.siteName }}</strong></h1>
                <a role="button" class="navbar-burger burger" aria-label="menu" aria-expanded="false" data-target="navbarBasicExample">
                <span aria-hidden="true"></span>
                <span aria-hidden="true"></span>
                <span aria-hidden="true"></span>
            <div id="navbarBasicExample" class="navbar-menu">
                <div class="navbar-start">
                <!-- Place holder for navbar start items -->
                <div class="navbar-end">
                    <div class="navbar-item">
                    {{ range .Site.Menus.main }}
                        <a href="{{ .URL }}" class="navbar-item ml-05 mr-05">
                        {{ .Name }}
                    {{ end }}

7. Create content for the Home Page

Open and edit layouts/index.html adding

{{ define "main" }}
    <div class="hero is-fullheight-with-navbar" style="background: grey url('{{ .Site.Params.herobackgroundimage }}') no-repeat center/cover;">
        <div class="hero-head">
            <!-- Placeholder -->
        <div class="hero-body">
            <!-- Placeholder -->
        <div class="hero-foot pb-2 pl-1">
            <div class="container has-text-">
            <p class="title is-size-5-touch is-size-4-tablet has-text-light">
                {{ .Site.Params.heroTitle | markdownify}}
            <p class="subtitle is-size-6-touch has-text-light">
                {{ .Site.Params.herosubtitle | markdownify}}
{{ end }}

Open and edit config.toml and add

    heroTitle = "Hero Title"
    herosubtitle = "Hero subtitle"
    herobackgroundimage = ""

Some comments on this code

a) Background Image

  • I’ve defined a background hero image for using in-line styles and add a link to the Parameter herobackgroundimage,
  • while this is not best practice (we should use the external style sheet main.css) it is because
  • Hugo doesn’t allow us to add a link to a Parameter {{.Site.Params.herobackgroundimage}} inside a CSS file
  • This allows you to change the background image, by updating the parameter in config.toml

b) Placeholders

  • I’ve added placeholders for CSS classes hero-head and hero-body, this does two things
  • Firstly I can then define a text strings in config.toml and link to them, and
  • Secondly I found Hugo wasn’t playing nicely with Bulma, and this seemd to fix it

c) Links to Parameters

  • I’ve added links to the parameters heroTitle and herosubtitle defined in config.toml

Your front page should look something like this (but with a different image)

Basic home page

8. Google Tag Manager and Google Analytics

I use Google Tag Manager to insert tracking codes into our website. This includes Google Analytics.

Open and edit config.toml and add

    googletagmanager = “GTM-XXXXXXXX”

Where GTM-XXXXXXXX is your unique Google Tag Manager ID.

Open and edit layouts/partials/head.html adding

    <!-- Google Tag Manager -->
    {{ if not (in (string .Site.BaseURL) "localhost") }}
        <script>(function(w,d,s,l,i){w[l]=w[l]||[];w[l].push({'gtm.start': new Date().getTime(),event:'gtm.js'});var f=d.getElementsByTagName(s)[0],j=d.createElement(s),dl=l!='dataLayer'?'&l='+l:'';j.async=true;j.src=''+i+dl;f.parentNode.insertBefore(j,f);})(window,document,'script','dataLayer',`{{ .Site.Params.googletagmanager}}`);</script>
    {{ end }}
    <!-- End Google Tag Manager -->

Open and edit layouts/partials/header.html adding

    <!-- Google Tag Manager (noscript) -->
    {{ if not (in (string .Site.BaseURL) "localhost") }}
        <noscript><iframe src="{{ .Site.Params.googletagmanger }}" height="0" width="0" style="display:none;visibility:hidden"></iframe></noscript>
    {{ end }}
    <!-- End Google Tag Manager (noscript) -->

You can then set up Google Analytics using this set of instructions by Google.

9. Next Steps

Over the next few posts I’m going to

  1. Add blog and static pages
  2. Change the layout of the list pages to include featured images, post titles & tags
  3. Add pagination to the list pages
  4. Add contact and newsletter sign up forms

I’m very grateful that other developers blog about code.

The sources for these posts on Hugo that I’ve read, and which I’ve used to build my website

I apologise if there are any mistakes or omissions, the errors are all mine.

If you find a mistake, I’d be grateful if you highlight it in the comments below.



comments powered by Disqus