How to build a static website with Jekyll

Getting started with Jekyll, a free and open source static site generator

Find out how to build your first static website with this Jekyll tutorial.

Getting started with Jekyll, a free and open source static site generator
Image by : 

Internet Archive Book Images. Modified by Opensource.com. CC BY-SA 4.0

Jekyll is a free and open source static site generator. Like a content management system (for example, Drupal and WordPress), Jekyll can be used to build websites with rich and easy-to-use navigation. Unlike Drupal and WordPress, however, Jekyll generates all the content at once, instead of waiting for people to visit your website's pages.

This model is well suited for an open source project's website because it reuses concepts that are already in use for source code, such as version control. The main disadvantage, of course, is that your site will completely lack dynamic features. These include "recommendations" specific to each visitor, user comments, or a fancy administration interface; the site's content will be the same for every user. On the other hand, a static site inherently is more secure, because Jekyll runs on your machine and is not exposed to malicious actors from the Internet. The setup on the server will be simple, too.

Jekyll was featured on Opensource.com in February 2016 ("6 reasons to blog in Markdown with Jekyll"). I recently used it to create a website for QEMU, one of the open source projects that I work on at Red Hat. In this article, I will provide tips for first-time Jekyll users, guide readers through the creation of a new Jekyll website, and look at Jekyll's theming and customization features.

Getting started

The simplest way to install Jekyll is through RubyGems. RubyGems is available for most GNU/Linux distributions; on Fedora, for example, you can install it with dnf install rubygems.

Once RubyGems is installed, the following steps will install Jekyll and create the scaffold for a new Jekyll site in the test/ directory:

gem install jekyll
jekyll new test

The directory contents will look like this:

-rw-r--r--. 1 pbonzini pbonzini  525 15 mar 11.50 about.md
-rw-r--r--. 1 pbonzini pbonzini 1402 15 mar 11.50 _config.yml
-rw-rw-r--. 1 pbonzini pbonzini  953 15 mar 11.50 Gemfile
-rw-rw-r--. 1 pbonzini pbonzini 1180 15 mar 11.51 Gemfile.lock
-rw-r--r--. 1 pbonzini pbonzini  213 15 mar 11.50 index.md
drwxrwxr-x. 2 pbonzini pbonzini   50 15 mar 11.50 _posts/

The two .md files are the source code for the website's pages. You can create as many directories as you want, and Jekyll will scan them for .md and .html files. Other Markdown files reside in the _posts directory; they are handled to provide features specific to blogs, such as post dates and categories.

Each source file consists of a front matter describing the characteristics of the page, followed by the page content in Markdown or HTML format. Here is the beginning of about.md:

---
layout: page
title: About
permalink: /about/
---

This is the base Jekyll theme. [...]

Everything between the --- is the front matter. It is written in YAML, a human-readable format that Jekyll uses for structured data. The front matter rarely if ever uses fancy YAML features.

To generate a page, Jekyll takes a layout from the theme's template (in this case, the "page" layout) and merges it with the data from the front matter and the page content. The front matter also tells Jekyll where to put the result (in this case, in /about/index.html).

Now enter the directory, type bundle exec jekyll serve (if you work on multiple websites, bundle exec ensures that you use the right version of Jekyll), and point your web browser to http://127.0.0.1:4000/. You'll see this:

The sample site created with "jekyll new", as shown by Mozilla Firefox.

The sample site created with "jekyll new," as shown by Mozilla Firefox.

Your website has already been converted to HTML, and the result placed in the _site/ directory:

drwxrwxr-x. 2 pbonzini pbonzini   23 15 mar 11.54 about/
drwxrwxr-x. 2 pbonzini pbonzini   21 15 mar 11.54 assets/
-rw-rw-r--. 1 pbonzini pbonzini 3836 15 mar 11.54 feed.xml
-rw-rw-r--. 1 pbonzini pbonzini 5301 15 mar 11.54 index.html
drwxrwxr-x. 3 pbonzini pbonzini   19 15 mar 11.54 jekyll/

This article does not cover deployment of Jekyll through a web server. Nevertheless, that Jekyll is also the engine behind GitHub's "pages" feature is worth mentioning; naming a GitHub project "example.github.io" is enough to have your static site generated and published at http://example.github.io/. In this case, however, you will lose the ability to customize your website with non-standard plugins.

Configuration

Among the files created by jekyll init is _config.yml, which provides global configuration to Jekyll. Like the front matter, this file is in YAML format.

The Jekyll documentation explains the various settings in detail. The defaults are usually good; in my experience, I mostly used _config.yml to customize the operation of plugins, which I will talk about later in the article. One exception is the default for the permalink option, which is:

permalink: /:categories/:year/:month/:day/:title.html

In case you noticed the jekyll/ directory in the generated website, that is where it comes from! The sample website includes an example blog post, and jekyll is simply one of the categories.

I think this is a fairly strange permalink format; fortunately, changing it is as simple as adding one line to _config.yml:

permalink: /blog/:year/:month/:day/:title/

Themes

Sadly, many open source projects have websites that look like they have last been updated in the 1990s, only without "under construction" GIFs. Often, the problem is simply the author's lack of experience as a designer. If that's the case for you, you should probably look for a good free template and adapt it to your needs. jekyllthemes.org offers many sample themes to start from. Many are hosted on GitHub and already have a Gemfile; in that case, you can clone the repository and start using them immediately:

git clone https://github.com/daviddarnes/alembic jekylltest2
cd jekylltest2
bundle install
bundle exec jekyll serve

If you chose a theme that does not have a Gemfile, you could use jekyll serve directly, without going through bundle, but you may encounter backwards-compatibility problems in the future. Creating your own Gemfile is better, and can be as simple as this:

source "https://rubygems.org"
ruby RUBY_VERSION
gem "jekyll"
group :jekyll_plugins do
   gem "jekyll-feed", "~> 0.6"
end

Your own theme

Many websites offer CSS and HTML5 templates that are released under a free Creative Commons licenses and can be used gratis. Two examples are TEMPLATED and HTML5 UP!, which provide hundreds of responsive themes, and each of them comprises at least a homepage and a second-level page. For QEMU's website, I started from their Linear template, although the result doesn't look much like it at all.

Not all of the themes you'll find are suitable for a blog—on the other hand, you may not be using Jekyll's blogging features—so make sure that your template is a good match for the features you will need in your website. For example, if you are going to use Jekyll for a blog, you should probably restrict yourself to templates that have an optional sidebar. The sidebar can be used to link per-month or per-category archives.

Make sure you check the requirements of the template in advance. For example, one controversial aspect of themes from both TEMPLATED and HTML5 UP! is that they use JavaScript to provide aspects of responsive behavior and even page styling. Some of your visitors might disable JavaScript, and even if they don't, visitors may see a "flash" of unstyled content in the browser while the JavaScript loads. In my case, I removed this library, and replaced it with simple CSS files without sacrificing the responsiveness of the page. CSS makes having separate stylesheets for "mobile" and "desktop" viewers easy, and adding a menu button for mobile users only requires a dozen lines of JavaScript code. If you don't want to do this kind of work, check the requirements of the template in advance.

Because you'll edit Jekyll pages and layouts with a text editor, you also should ensure that your template has readable HTML and CSS; some designers use "minified" HTML and CSS code in their demos, and only offer the actual source for a fee.

Starting from the scaffold created by jekyll new, you can add your theme's source code directly in the Jekyll source code directory. As mentioned earlier, Jekyll's templating system works by defining multiple layouts, which are stored in the _layouts/ directory. QEMU website has three main layouts, which is quite typical:

  • home for the home page,
  • page for website pages (without sidebar),
  • and blog for blog pages (with sidebar).

The blog layout is further specialized into one for blog posts and one for archive pages.

Large parts of the HTML source code can be shared by different layouts. Use Jekyll's templating system to avoid duplication, and place these common elements in a separate file in the _includes/ directory. All of the HTML header with links to CSS and JavaScript libraries, the navigation menu and site map, the credits, and the blog sidebar can be extracted in this manner.

If you clicked the links, you'll have noted more advanced content in the files, such as template directives. Don't worry; you can easily start with placeholder content from the CSS/HTML template. Most Jekyll templates organize their _includes directory in a similar way, and incorporating these advanced elements from the standard Jekyll template, from other tutorials or, from QEMU's website will be fairly easy.

Advanced features

What I presented so far should be enough to build a functional web site that is unique to your project. However, Jekyll provides many more features that can make your website better and your work simpler. For the QEMU website I used two: plugins and collections.

Plugins

Jekyll's plugin system provides hooks to run custom Ruby code at site generation time. There are several kinds of plugins, the most common of which are generators and tags.

Many plugins exist in the form of Ruby gems; the Jekyll documentation again explains how to add the gems to your Gemfile and install them with bundle. jekyll new already configures the jekyll-feed gem; jekyll-feed is a generator plugin that produces a feed of blog posts in Atom format.

Sometimes, however, existing gems do not provide exactly what you need. In this case, your website can use a custom plugin.

Example plugin: Blog archives

Generator plugins let you add directories and files to Jekyll's output. Their Ruby code defines a subclass of Jekyll's Generator class, and a generate that can produce an arbitrary number of output files. For example, a generator subclass could look at all posts in the website, group them by month, and produce an archive page for each month.

In fact, this is exactly what the monthly archive plugin does. QEMU uses this plugin and links to the monthly archives from the blog's sidebar. Another similar plugin generates category-based archive pages, which are linked at the bottom of each blog post.

These plugins are highly customizable. I mentioned earlier that the layout of the archives is in a separate file, residing in the _layouts/ directory. _config.yml tells the plugin which layout to use and how to format the URLs:

monthly_archive: {
  path: 'blog', layout: 'archive'
}
category_archive: {
  path: 'blog/category', layout: 'archive', slugify: true
}

Example plugin: MarkDown includes

In addition to generating pages, plugins can also be used to add new commands to Jekyll's templating system. The QEMU website uses one such plugin to simplify its page, arguably the most complex in the site.

This page has a horizontal menu that lets you choose which of four panes to display. The menu is implemented using HTML and JavaScript, and the code for it is quite long. Keeping the content of the panes separate is desirable, and, while I was at it, I thought writing it using Markdown instead of HTML would be nice. Strangely enough, Jekyll's include and include_relative directives only let you include HTML. In my case, I wanted something like include_relative (which includes a file from the current directory rather than _includes/), except with Markdown support.

The solution is only 20 lines of code; the whole plugin fits in a single file that you can drop in the _plugins/ directory. It provides two new template directives— markdown and markdown_relative—the latter of which was exactly what I needed.

Collections

Another interesting feature of Jekyll is collections. Collections help with including structured data in your website—by splitting the data from its presentation, they make the task easier and less error-prone.

Collection data is stored in the _data subdirectory and is formatted in YAML, like this:

- name: Paolo
  birthday: March 17
- name: Luisa
  birthday: November 28

If the above four lines are stored in _data/birthdays.yml, templates will be able to access it as site.data.birthdays. The following Liquid code:

{% for person in site.data.birthdays %}
<p>{{person.name}}'s birthday is on {{person.birthday}}.</p>
{% endfor %}

will be transformed to:

<p>Paolo's birthday is on March 17.</p>
<p>Luisa's birthday is on November 28.</p>

I used collections in QEMU's website to represent our releases and the screenshots for the home page gallery. In both cases, the presentation is further abstracted in an include file such as this one for releases. The releases collection is particularly useful; the QEMU release process is long, and the nice YAML format minimizes the burden of updating the website.

Conclusion

Using Jekyll to build QEMU's new website was really fun. I was able to build a first version of the website in about a day, and the learning process remained soft as I polished it according to user feedback from Reddit and the QEMU IRC channel. I hope the tips I shared in this article can help you, too.

Comment now