Themes and Templates

This post was started on 2020-12-18. It was published on 2020-12-18.

With the most recent refactoring, Colophon has a basic, but functional theming system. Since Colophon is a system for building websites, themes are written as CSS (though in the future themes could be written in something like CSS-expressions).

For now, Colophon themes only allow for customizing the colors of various elements using CSS variables. In the future, this could be extended to customize fonts and other layout elements. But to properly understand how these themes work, we need to know a little about how Colophon handles styling and CSS in general.

The default <head> tag for an HTML page generated by Colophon contains a number of <link> tags for CSS stylesheets. In particular, there is a fonts.css (that we will ignore for now), a stylesheet.css and a theme.css. The stylesheet.css file contains most of the styling for the page: margins, padding, fonts, everything that defines the basic look and feel of the page. However, most of the time a color is required, this file uses CSS variables instead of direct hex or RGB values. The values corresponding to these variables are defined in theme.css. To change the colors in use, we just need to provide a different CSS file with the colors of our choice.

But there’s more! Each theme can have any number of variants by providing a different set of these values for these variables. For example, the default Grayscale theme that this site uses has both a light and a dark variant (since dark mode is the new hotness these days). The theme.css file for Grayscale provides selectors for .theme-light and .theme-dark as follows:

.theme-light {
    --bg-color: #f7f7f7;
    --bg-alt-color: #222222;
    --bg-sel-color: #cce3ee;
    --text-color: #333333;
    --text-alt-color: #f7f7f7;
    --text-sel-color: #222222;
    --text-hdr-color: #000000;
    --code-text-color: #222222;
    --code-bg-color: #fbfbfb;
    --link-color: #0077aa;
    --link-visited-color: #66adcc;
    --link-bg-color: #f7f7f7;
    --border-color: #0077aa;

.theme-dark {
    --bg-color: #333333;
    --bg-alt-color: #f7f7f7;
    --bg-sel-color: #cce3ee;
    --text-color: #f7f7f7;
    --text-alt-color: #333333;
    --text-sel-color: #222222;
    --text-hdr-color: #66adcc;
    --code-text-color: #222222;
    --code-bg-color: #fbfbfb;
    --link-color: #66adcc;
    --link-visited-color: #0077aa;
    --link-bg-color: #333333;
    --border-color: #0077aa;

So far so good, but how does one go about using these themes and theme variants? This is where Colophon’s templating system comes in. Really, this is Pollen’s template system, but Colophon provides some handy functions to make writing them easier. In particular, Colophon provides the head-with and body-with functions for generating HTML <head> and <body> tags, but with Colophon-specific components. The head-with takes a #:theme argument that is a URL to a CSS file, and body-with has a #:theme-variant that lets you specify a theme variant (light or dark in the case of the Grayscale theme). The template for these post pages looks like this:

<!DOCTYPE html>
<html lang="en">
  ◊(->html (head-with #:theme "/css/grayscale.css"))
  ◊(->html (body-with
            #:navigation (navbar)
            #:theme-variant "light"
                `(article ((id "content"))
                          ,@(make-top metas)
                          ,@(remove-tag more-tag (select* 'root doc)))))

    <!-- Copyright notice goes here -->


As you can see, the post template is HTML with some Pollen code sprinkled in to do the heavy lifting. The body-with function lets you build up the page by providing a navigation bar (with "#:navigation") and the main contents (with #:contents). In this case, we’re using a navbar we defined elsewhere and then used some Colophon utility functions to put the contents of a post inside an <article> tag, automatically generate some top-matter and remove the more tag that tells Colophon where to stop when generating an excerpt.

Right now, the theme and templating system is admittedly a little inelegant. It readily exposes the fact that we’re just hooking up various pieces of HTML and CSS. It also has quirks like requiring the theme to be part of the <head> tag, but the variant to be in the <body>. Changing a theme also requires editing (possibly multiple) templates, which is going to be a pain if you want lots of different types of pages. These are all things I’d like to address once Colophon’s core functionality is a little more fleshed out. But for now, it gets the job done, and I think the basic ideas of how it works and is implemented are solid, while allowing for future user-facing improvements.