Building a website in Markdown with Pandoc

Fast Web

© Lead Image © Martin Blech, Fotolia.com

© Lead Image © Martin Blech, Fotolia.com

Author(s):

Build a simple web page in Markdown; then convert it to HTML at the command line.

Creating a website is a lot of trouble – especially if you just have a few files you wish to publish online. You could type in all the HTML codes by hand, or you could employ a graphic design tool that looks simple but still might be more effort than you want to spend.

Another easier option is to use Pandoc [1]. Pandoc is a universal document converter. You can give Pandoc a text file in any of several markup formats, and it will convert the document to any of several output formats. One common scenario is to format a text file using the simple and expressive Markdown markup language and then use Pandoc to convert the file to an HTML page. Pandoc is a command-line tool, so it allows you to convert a file to HTML in a single command. A collection of command-line options lets you add extra features to the web page, such as a footer bar or a rudimentary navigation menu. With the right libraries, Pandoc can even read programming languages.

You wouldn't want to use Pandoc for a complex site with interactive features and a backend database, but if you are just looking for a quick-and-dirty tool for publishing text to the web, Pandoc is a very good option. For instance, some organizations use Pandoc in situations where there is a need to maintain documentation that is accessible from the command line but still easily convertible to HTML.

Markdown Magic

The scenario begins with a text file in Markdown format. This article is not intended as an introduction to Markdown, but if you're looking for a primer, you'll find several cheat sheets and tutorials online [2]. Listing 1 shows a sample Markdown file. As you can see, the format is largely self-explanatory.

Listing 1

Sample index.md

01 # Escape Mundane Life
02
03 On this website, you will never be ~~BORED~~!
04
05 ## Fun Jokes
06
07 Well, come up with something yourself!
08
09 ## Pure science
10
11 The best way to get to the truth about werewolfs!
12
13 | Moon phase      | Phang size | Measurement time | Result |
14 | ---             | ---        | ---              | ---    |
15 | New Moon        | 0.1        | 00:14            | Skinny |
16 | Waxing Crescent | 0.2        | 00:21            | Skinny |
17 | First Quarter   | 0.6        | 00:09            | Normal |
18 | Waxing Gibbous  | 2.3        | 00:32            | Strong |
19 | Full            | 9.3        | 00:19            | Bulky  |
20 | Waning Gibbous  | 6.1        | 00:59            | Dirty  |
21 | Third Quarter   | 0.8        | 02:01            | Flappy |
22 | Waning Crescent | 0.2        | 00:01            | Skinny |
23 |                 |            |                  |        |
24
25
26 ---
27
28 ```
29 {
30     "Human name": "Ben";
31     "Wolf Name": "Slasher";
32     "age": "32"
33 }
34 ```
35
36 > Conclusion
37 > Ben is a *Werewolf* who should build his human body! [^1]
38
39 ## A link to the city.
40
41 - Some Pictures!
42   1. A bustling City!
43
44      ![Big City](https://www.abc.se/~m9779/images/Storstan.bmp)
45
46   2. Chilling in the bay!
47
48       ![Some boats](images/boats.bmp)
49 ---
50
51 [^1]: Ben is fictive name.
52 <C>

You will quickly notice Markdown features such as headings (with # for a top heading and ## for a second-level subhead). Double tilde makes the text strikeout. You can also make tables with a simple combination of pipes | and dashes -.

To convert the Markdown text in Listing 1 to an HTML page, run the standard Pandoc command:

$ pandoc -t html index.md -o index.html

Pandoc outputs to standard output unless you specify an output file with the -o parameter.

Structure

Your Pandoc-generated website will be simple and relatively sparse, but you will still want to be methodical about keeping it organized. Pandoc only generates one page at a time, so to reduce clutter and confusion, set up a basic directory structure for your source files – something like in Figure 1.

Figure 1: This sample tree is a suggestion, but make sure you know where your original text is and where you put your result!

In the src/ directory, put your index.md, about.md, and other Markdown files you will convert to HTML for your site.

Options

The pandoc command has many additional options. By default, Pandoc creates document fragments. If you would like to output a standalone HTML document (with <head> and <body> sections), use the -s or --standalone option. The --standalone flag supports some other options for where to locate text:

- -H --include-in-header=
- -B --include-before-body=
- -A --include-after-body=

A CSS file is required when generating an ePub but is optional for simple, standalone pages.

If you want to maintain your site using many files, you can list all the files as input and output straight to one file.

pandoc *.md -o index.html

This command will process all the .md files in the order they would have been listed by ls. In most situations, you will want more control over where the content falls within the output file, so processing the files in ls sort order has some complications – you might want to consider more sophisticated techniques.

Styling with CSS

Styling should occur in a separate file, outside of the page. Any file you point to with the -H option will be copied in, and that can include a CSS file as part of the final directory structure.

Usually, you will start by using an existing style. In this example, you can copy the Tufte CSS file into one of your sub-directories and add the link to a header file:

<link rel="stylesheet" href="Tufte/tufte.css"/>

Footer and Header

If you want your website to look tidy and professional, you might want the site name and URL to appear in a header or footer bar to let people know where they are regardless of which page they are on.

As mentioned previously, the options -B (before the body) and -A (after the body) let you create headers and footers. You could use these options to create a navigation bar at the top or a consistent footer for all pages. You can repeat these options as many times as you like, though the final result will suffer if you overdo things.

To create the header text you want, save the text in a file and specify the file name with the pandoc command using the -B option (Listing 2).

Listing 2

Specifying Headers and Footers

$ pandoc -t html\
        -H head.html \
        -s -o index.html \
        -A footer.html \
        -B toptext.html \
        --metadata title="Kick Mundane Out"
        index.md \

Note that Listing 2 also brings in the CSS style sheet using the -H parameter. In this case, the head.html file only contains a link to the stylesheet.

Suppose I wish to add a copyright notice at the bottom. You can also imagine other things that might appear in a footer, such as social links and other legal information. The footer id tag is common in CSS stylesheets (Listing 3).

Listing 3

footer.html Footer

footer.html
<C>
<div id="footer">
    &copy; 2021 Mats Tage Axelsson
</div>
<C>

A simple nav bar in the header could show the other pages on the site in a list (Listing 4).

Listing 4

toptext.html Header

<C>
<div id="nav-bar">
    <ul>
        <li>Home</li>
        <li>projects</li>
        <li>About</li>
    </ul>
</div>
<C>

Templates

When you convert to a new format, Pandoc will use a default template. Alternatively, you can create your own template. The easiest way to create a template is to write an existing template to your directory and edit it:

pandoc -D html > MyTemplate.tmpl

The simplest sites do not need templates. However, templates provide a means for incorporating variables and simple conditionals that add power and convenience to your web presence.

A template is a file in the final format that you seek – in this case, HTML files. The big difference between a template and an ordinary file is that templates have variables embedded. In short, variables are enclosed in dollar signs, and you assign values to those variables using your defaults file or command-line options.

For instance, you could use a metadata variable as a placeholder for a title. Then in the defaults file or as part of the pandoc command, you could specify a title for the page:

--metadata title="Escape Mundane Life"

If the title shows up in the default template, it comes with conditions. Pandoc checks if title is defined elsewhere, and if not, it puts it in (Listing 5).

Listing 5

Conditional Default Title

01  $if(title)$
02 <header id="title-block-header">
03 <h1 class="title">$title$</h1>
04 $if(subtitle)$
05 <p class="subtitle">$subtitle$</p>
06 $endif$

As you can see, Listing 5 defines both the title and subtitle.

Some ready-made templates are available to help you add common features to your website. For instance, the pandoc-bootstrap [3] template includes several elements that add value to your site. Bootstrap sets up CSS and connects to some JavaScript to give you a navigation bar and maybe a table of contents. You can also add an author name and a date.

In the code, you define where you want the variables to go:

$for(author-meta)$
  <meta name="author" content="$author-meta$" />
$endfor$
$if(date-meta)$
  <meta name="date" content="$date-meta$" />
$endif$

There are two ways of setting the values; one method is to add a YAML block [4] at the top of your document, in this case, index.md.

The three dashes indicate the start and end of a block:

---
subtitle: "More creativity"
author: "Mats Tage Axelsson"
date: "2021-08-12"
---

The other way to set the variables is with the -V parameter. For instance, note that the command in Listing 6 sets the date using the -V variable.

Listing 6

Setting Variables with -V

pandoc index.md\
     -o index.html\
     -s\
     -t html5+smart\
     -V date="2021-08-15"\
     -M subtitle="More Vitality"\
     --template ../pandoc-bootstrap-adaptive-template/template.html\
     -B toptext.html\
     -A footer.html\
     -c ../pandoc-bootstrap-adaptive-template/template.css\
     --metadata title="Escape Mundane Life"

As you can see in Figure 2, the data is added to your web page.

Figure 2: After you have added the metadata in the command, the date shows up in the right hand top corner, thanks to CSS.

Slides

Pandoc has built-in support for slideshows and supports several different slideshow standards. Regardless of which output format you wish to use, the format of your source document will be in Markdown.

Begin each slide with a horizontal rule. A slide-level header also starts a new slide. If you want to have notes available while you are present, just add them using the ::: notes tag, closing it with :::.

Adding notes is really simple; styling them is a little trickier – CSS to the rescue. If you are using reveal.js, you set all variables as you would without Pandoc. Otherwise, you can set styling using a directory under your Pandoc $DATA-DIR$ – usually ~/.pandoc; standards are available in the system directory.

The command is the same as usual – just choose the output format you like.

pandoc -t slidy -i slideshow.md -o site/slideshow.html -s

You should be able to pick up more information from the web sites that support the slideshow standards.

Converting to HTML

One command with many input files will create one output file. A more conventional approach is to create one page for each of the parts of your site. This approach also enables blogging-like functions, if you do it right. The simple script for creating multiple output files is shown in Listing 7.

Listing 7

Multiple Output Files

#! /usr/bin/env bash
for page in $(ls pages); do
  pandoc --from markdown_github+smart+yaml_metadata_block+auto_identifiers "pages/$page" \
    -o "public/$(basename $page .md).html" \
    --template templates/page.html\
    -V navigation="$(cat navigation.html)" \
    -V footer="$(cat footer.html)"
done

To use the script in Listing 7, you have to create the tree structure, including a pages/ directory that has all the pages for your site. On top of the pages/ directory, you have the templates and files that the command references (templates/page.html, navigation.html, and footer.html). The complete code is available online [5].

To take full advantage of these templates, and make your own template, look through the code, and set any necessary variables.

MkPage

A good front end can make things easier. One such front end is MkPage [6].

The MkPage Project uses Pandoc and its template language and adds a few tools, allowing you to define the entire site in a small project directory. All the tools follow *nix standards. To run MkPage, you set values on the command line that matches the variables in your template file.

You can use all tools in the project separately. Available tools include the main MkPage tool, as well as a tool called BlogIt and others. As you might guess, the BlogIt tool lets you write all your blog posts in Markdown.

Conclusion

Using Pandoc to create a static website in Markdown will save you from using big, complicated build systems on the web or writing your own HTML. This option is not suitable for developing advanced websites. The emphasis is on creating small, functional sites that present you or your offerings in the best possible light without a lot of complications.

The Author

Mats Tage Axelsson has a set of modes that he still has not found the keyboard shortcut to change.