Theme
Font

Zola in Five Minutes

7-minute read

While described as a kind of “batteries included” SSG, I don’t think this is the case. Zola, in my experience, has proven to be just another SSG that has opinions on defaults.

It doesn’t help that the generator seems to be for those who don’t design for the web, and would prefer to write in Markdown with a preconfigured theme.

Its documentation separates content and templating, which is nice theoretically, but also just leads to separation of a lot of related (or exactly the same) content.

I come from Eleventy, a JavaScript SSG that allows you to write all its functionality in one JavaScript file, so when I was shopping for a new generator, the main criteria was

and Zola, in a way, fails at both.

Reading the directory structure page at first glance with these criteria would turn one off, and it certainly did for me, but after parsing through the way the entire thing comes together, it makes a lot more sense.

To begin with, themes, static, and sass are in practice optional.

For me, the directory structure looks more like (abridged)

Sass compilation is optional, so if you prefer to write pure CSS it would just go in static/ (which is how Sass is compiled in the first place).

Templates, however, are not.

One thing that forces you to adopt the Zola way, though, is that content can’t have templating (aside from a dedicated templates/shortcodes/ directory, which is more advanced and not how to do single-page templating).

Strangely, this is a good thing. Your content has to extend from a layout. Zola won’t serve an HTML file as a “page”, but it will if it considers it a static asset to a post. This complicated my shrine page, since every single shrine there is written in raw HTML. They can’t be served by Zola, but they can be linked to with a .html extension.

I think it would benefit Zola greatly if the distinction between the root page, different sections, and pages were removed.

My first attempt at building this site led to extreme annoyance with the fact that the root page couldn’t be written in Markdown as a “page”. What I failed to understand then is that it is, as long as you eliminate the distinction in your mind.

“Pages” are named either yyyy-mm-dd-slug.md or index.md in a folder with that name sans .md. “Sections” are named only _index.md and inherit the name from the directory.

Assets for each post or section can be colocated, so static/ is mainly just for global sitewide assets. Everything there is copied to /.

The default templates also go in templates/. Section’s default is section.html and page’s default is page.html.

But. The root document content/_index.md must be a section, and its default is index.html, not section.html.

A 404 page’s default is 404.html, and a few global configuration options in config.toml will enable or disable automatic generation of things like sitemap.xml, rss.xml, atom.xml, and robots.txt. Each of these files has a default template that you can override, but if you do, you have to write the entire thing from scratch.

Coming from Eleventy, my default automatic template was html.html which would create an HTML document that every page would have by default using variables like {{ title }}.

This can be done, counter-intuitively, by using index.html, which in some configurations often inherit from section.html, as this page.

The way that Zola does templating, with Tera, is fundamentally different from the way I was used to.

A template file consists of content that is overridden by blocks.

If we write

<!doctype html>
<main>
	{% block content %}No content!{% endblock %}
</main>

in index.html, any other file with

1{% extends "index.html" %}

in the template directory will copy the same content.

We can then add

3{% block content %}
4 This is a section.
5
6 {{ section.content | safe }}
7{% endblock %}

to template.html.

The final compilation of this, with

+++
+++

# Welcome!

Hello, world!

in content/blog/_index.md, is a document at /blog/ that finally reads

<!doctype html>
<main>
	This is a section.

	<h1>Welcome!</h1>
<p>Hello, world!</p>
</main>

There’s another way to do this, without direct inheritance, but using it is mutually exclusive with {% extends %} and I find it less elegant. For me, it needlessly increases verbosity.

I write my index.html with all the boilerplate layout information that every page needs to have, then for sections implement a custom listing that changes based on how deep the post is in the year.

Zola does, I forfeit, have many niceties that have let me create a truly static page where others would resort to client-side JavaScript.

With that said, these are more or less buried in the documentation, and even in that page, it’s all just explained with code comments. The same goes for implementing taxonomies, probably the best way I’ve seen to implement post tagging, which is also terribly onboarded.

A taxonomy is basically a collection of collections, so on a page’s front matter you might have

[taxonomies]
tags = ["web", "design"]

The documentation on this (of which there are two pages, one to half-explain it and another for information on templating it) likes an example of a section with movies which would use

title = "Titanic"

[taxonomies]
directors = ["James Cameron"]
actors = ["Leonardo DiCaprio", "Kate Winslet"]
releases = [1997]

A table of contents with anchoring and footnotes are built-in, and that’s pretty awesome.

Getting code blocks to look nice was a hassle, though. By default, colors are inline-styled, which means that it can’t dynamically change theme.

You can make this CSS with highlight_theme = "css" in config.toml, but I’d only recommend this after you’ve generated CSS for a theme, so you have a starting place.

For me, I wanted to use Visual Studio Code’s theme as a kind of compromise, and make it work with both light and dark schemes, so I had to

1

We’ll just say that I moved away from Eleventy because JavaScript package management is crapdosis.