Minimal Jekyll blog from scratch

27 January 2019

Here goes a mandatory setting up your own Jekyll blog first-post.

Except in this one you don’t actually need to install Jekyll. Why not install Jekyll? Because Ruby + msys2 + Jekyll takes over 900MB (at least on Windows), which is beyond acceptable for just blogging. I also like to keep things minimal in order to understand what I am doing, and having hundreds of lines of script-generated boilerplate is diametrically opposed to that. Static sites are safer and better for many use cases. That’s not to say every site must be static.

The thing is you don’t actually need to install Jekyll because GitHub Pages just needs a jekyll-compatible structure in your repo and is more than happy to build it for you. This way you can add pages just by commiting new files to your repo (even from the GitHub web interface). I installed Jekyll only to figure out how it works and deleted it right after so you don’t have to.

How are we going to do it?

Creating a simple template

I chose a simple template just for demonstration purposes. It’s somewhat responsive and readjusts itself if the screen is too small. You should use it as a starting point and work on making it the way you want it, because I haven’t bothered to make it look pretty. Or if you’re versed on HTML/CSS, do it from scratch and skip this section.

Here’s what it is going to look like: Demo

Why not a super sexy, full of animation, JavaScript-ey, React single page application? Because this is for a simple mostly-text webpage. You don’t need a bloated SPA for serving text pages, when a static site will do. And you want it to be fast, so there’s no need to follow the web-bloat trend. Consider checking this, this and this for some inspiration.

The layout is comprised of two files. Create some directory in your computer and create the following files:

index.html, where the document structure is defined:

<!DOCTYPE html>
<html>
<head>
    <title>Example</title>
    <link rel="stylesheet" href="style.css">
</head>
<body>

<header>
    <span class="logo"><a href="">site name</a></span> 
    <ul class="navigation">
        <li><a href="/">Home</a></li>
        <li><a href="/">About</a></li>
        <li><a href="/">Blog</a></li>
        <li><a href="/">Some</a></li>
        <li><a href="/">Other</a></li>
        <li><a href="/">Stuff</a></li>
        <li><a href="/">Here</a></li>
    </ul>
</header>

<content>
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Morbi lacus felis, imperdiet at enim vitae, lobortis pulvinar magna. Vivamus interdum eros quam. Aliquam a mi lorem. Donec ut turpis neque. Sed mi massa, convallis sed venenatis ac, elementum eget lectus. Nulla ante tellus, iaculis a convallis pellentesque, efficitur id lorem. Mauris eget enim justo. Nunc iaculis luctus ex, eget dictum risus. Proin eu porttitor felis. Donec dapibus, mauris in ultricies tempus, libero turpis ullamcorper lacus, ac gravida risus nulla rutrum turpis. Orci varius natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Proin commodo convallis quam, in sagittis odio. Etiam elementum viverra luctus. Nam imperdiet placerat ipsum ut tristique. Integer in elit ex.

Integer hendrerit feugiat nisl, in vehicula libero ullamcorper quis. Nam tincidunt est ut condimentum ornare. Morbi at justo pretium, consequat massa hendrerit, mollis lacus. Vestibulum euismod condimentum semper. Aenean volutpat blandit tortor, id sodales odio. Nullam eleifend diam id diam dictum pharetra. Ut ut urna id velit imperdiet rutrum. Nam tempor commodo erat vel luctus. Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. In hac habitasse platea dictumst. Vestibulum ut urna dapibus, pretium neque ut, posuere tellus. Sed ultricies consequat velit ut auctor. Donec consectetur eu ligula aliquet interdum. Sed ipsum risus, eleifend a aliquam quis, euismod sed enim. Quisque sollicitudin, nulla pharetra interdum pretium, sapien quam porta eros, non pulvinar tortor ante et velit. Donec dapibus rutrum magna, quis suscipit sem fringilla eu.
</content>

</body>
</html>

and style.css, for positioning the elements and styling:

/* positioning */
body {
    padding: 0;
    margin: 0;
    display: flex;
    flex-direction: column;
    align-items: center;
}

header {
    width: 100%;
    padding: 5px;
    display: flex;
    align-items: center;
}

header .logo {
    flex-grow: 3;
    margin-left: 10%;
}

header ul.navigation {
    display: flex;
    flex-grow: 2;
    justify-content: space-around;
}

content {
    width: 80%;
    padding: 25px;
}

header, content {
    box-sizing: border-box; /* inner padding */
}

/* styling */
body {
    font-family: Helvetica, Arial;
}

header {
    background-color: gray;
}

.logo {
    font-size: 24px;
}

header ul.navigation {
    list-style: none;
}

content {
    background-color: lightgray;
    font-size: 0.9em;
}

header .logo a {
    color: white;
    text-decoration: none;
}

.navigation a {
    text-decoration: none;
    color: white;
    padding: 10px;
    display: block;
}

.navigation a:hover {
    background-color: black;
}


/* smaller screens */
@media all and (max-width: 500px) {
    body {
        font-size: 1.2em;
    }
    
    header .logo {
        display: flex;
        flex-direction: column;
        justify-content: space-between;
    }

    header, .navigation {
        flex-direction: column;
        align-items: stretch;
        margin: 0;
        padding: 0;
    }

    header .logo {
        margin: 0;
        padding: 10px;
    }

    header .logo, .navigation li {
        text-align: center;
    }

    content {
        width: 100%;
    }

    .navigation a {
        border-top: 1px white solid;
    }
}

The template is done using flex-box. It is easy and you probably won’t waste as much time randomly changing properties in order to vertically center elements. Consider checking this awesome visual guide to flex-box.

Jekyllize it

I’m assuming you have an idea what Jekyll is for. If you don’t, the TL-DR is that it will fill the gaps in your template with your markdown-formatted content so that you don’t have to do it yourself fiddling with a bunch of HTML files and making sure no links are broken.

You now have a simple layout for your web-page, you just need to tell Jekyll where to put stuff. You do so by using special tags which I’ll soon introduce. But first let’s separate some parts of the layout so we don’t have to copy-paste it for every different page we create. Start by moving style.css into an assets folder and updating the <link> reference in index.html with the following:

<link rel="stylesheet" type="text/css" href="/assets/style.css">

While we’re at it, rename index.html to default.html and move to a _layouts folder, since it is going to be our default template (we’ll only have a different one for displaying blog entries, where post title, author and date is displayed).

So far we have told Jekyll what our default layout looks like. But we still don’t have a page. We need to create one and make it use the default layout. We do so by creating a Markdown file where the first few lines are front-matter tags, which indicate some meta info about the page.

Create index.md on the project root:

---
title: Home
layout: default
permalink: /index.html
---
Hey this is the first page!

Now we have a page that uses the layout we created. This is also the part where if you were too stubborn and installed Jekyll anyways you can run jekyll serve from the command-line and checkout what your web-page looks like. If you didn’t install Jekyll, don’t worry. All you need to do is create a _config.yml with the following:

name: Example

After that, commit it, push it to your GitHub and navigate to your repository settings: Settings > GitHub Pages > Source > Select “master branch” > Save.

Now GitHub understands your repository is a Jekyll-powered static site and publish it. The URL will appear right above the dropdown where you selected the source branch.

Making content dynamic

There’s your page! Although it’s still displaying Lorem Ipsum and not the content we added in our index.md. In order to do so, strip off Lorem Ipsum (keep the content tag) from _layouts/default.html and replace it with this:

{{ content }}

Now the layout will render the contents of the index.md file. Let’s create another page!

Create about.md in the project root alongside index.md:

---
title: About
layout: default
---
This is an about page!

Notice we didn’t add a permalink tag here. Jekyll will create a page with the same name of the Markdown file. In fact, you didn’t even need it in the index.md, I just put it there in case you decided to name the file something other than index.

Dynamic navigation menu

There’s a problem, though. The “About” page is not showing anywhere in our menu and we are stuck in the “index” page. We can still access it directly via [YOUR URL]/about.html, where [YOUR URL] is either the GitHub-Pages URL for your repository or localhost:4000, if your accessing it by the jekyll serve command.

What we need to do is programatically retrieve the pages in our static site and list them in the top menu. So we go back to default.html and replace those <li> tags with this:

        {% for page in site.pages %}
        {% if page.title %}
        <li><a href="{{ page.url }}">{{ page.title }}</a></li>
        {% endif %}
        {% endfor %}

Now the top menu is displaying links to our pages. It might not be displayed in the order you want, so in this case you need to sort it first. Do so by adding a front-matter tag “order: n” to your pages (between the pairs of three dashes), where “n” is the desired order, and using this version of the snipped instead:

        {% assign sorted = site.pages | sort: 'order' %}
        {% for page in sorted %}
        {% if page.title %}
        <li><a href="{{ page.url }}">{{ page.title }}</a></li>
        {% endif %}
        {% endfor %}

Only the first two lines are different, and they are there to sort the pages by “order” before displaying them. Now, to keep things clean, move both index.md and about.md (and whichever other pages you have created) into a new folder called pages. If you want to add some pages that don’t appear in the menu, add some “menu: true” or “menu: false” tags to your pages and update the if statement to:

    {% if page.title and page.menu %}

You’re probably noticing a pattern here, where we are controlling how and if pages appear in our menu by adding front-matter tags and updating our Jekyll-directives (they’re called Liquid statements). That’s basically all you need to know if you just want to keep adding new pages. But the intent of this post if to show you how to make a minimal Jekyll-powered blog, and we haven’t touched on the “blog” part yet.

Making it an actual blog

Blog entries in Jekyll are just a special collection of Markdown files located in a folder called _posts. So go ahead and create your first entry named to something along the lines of _posts/2019-01-28-first-post.md containing the following:

---
layout: post
title: The post title
author: your name
date: 2019-01-28 02:19:15
---
This is the first post in the blog!

Fill out the front-matter tags accordingly, it should be self-explanatory. There’s still no page listing all blog entries, so we can’t find where that post went. Let’s create a page to list all the posts in pages/blog.md:

---
title: Blog
layout: default
order: 3
---
{% for post in site.posts %}
<ul>
    <li>{{ post.date | date_to_long_string }} - <a href='{{post.url}}'>{{ post.title }}</a></li>
</ul>
{% endfor %}

This snippet lists all blog entries in reverse chronological-order (most recent on the top). Now our visitors can access our posts.

There’s one last problem. If you have a keen eye, you might notice we don’t have a “post” layout. That’s why when we click the links to our posts they’re black-on-white pure-text.

We need to create this layout, so create a file _layouts/post.html with the following:

---
layout: default
---
<h1>{{ page.title }}</h1>
<h2>{{ page.date | date_to_long_string }}, <i>{{ page.author }}</i></h2>

{{ content }}

We’ve taken advantage of the pre-existing default.html layout and included some more info alongside with the content (post title, date and author).

Publish it

This wraps up the basics for creating your own blog with Jekyll from scratch. In order to publish, just commit your work and push it to GitHub, set the source branch for GitHub Pages if you haven’t already:

Settings > GitHub Pages > Source > Select "master branch" > Save.

And you’re done! GitHub will soon build and publish your blog for you. Since you’ve built it all from scratch, you should be more familiar with it than if you had used a generator for your site. Now you’re no longer limited to using templates which were made specifically for Jekyll. You can create your own or turn someone else’s template into a Jekyll-compatible one. You also don’t even need to have it installed in your computer, and are able to add new posts and pages straight from GitHub web-UI.

Hopefully I covered most of what you need to get started. For everything else, Jekyll docs and Google got you covered.

I hope you’ve enjoyed the ride.

You can find the accompanying code for this tutorial on this GitHub repository. And here’s a live demo. You may also just fork it, rename the repo to <yourusername>.github.io and start from there.

Extras

Coming soon in a new post, perhaps?

Code blocks with highlighting

Adding a comment section

Gotchas

If you’re working on a GitHub page for a project instead of for your user (i.e. username.github.io/project-name), you’ll likely find some problems with broken links. You need to set “baseurl” in your _config.yml and update how you do your links. Here’s the solution.