DEV Community

Cover image for Customize Your Jekyll Website

Posted on • Updated on • Originally published at

Customize Your Jekyll Website

This article is part of a series showing you how to quickly and freely build and host your own Jekyll blog on GitHub Pages. This series will also cover more advanced topics like adding a comment system directly in our code using Staticman and adding privacy-friendly but still free analytics using Umami.

I divided the tutorial into several parts:

Now that we have started adding content to our website, let's see how we can customize its appearance.

How Jekyll generates pages

One of the reasons I like Jekyll is that it provides you a very clean directory as it hides most of the magic behind the website creation.
However, the drawback is that it is easy to feel lost and not to know how to update your theme when it comes to customizing it.

Indeed, layouts are defined by your theme and are not present in your local folder.

So before doing anything, we need to look at our minima theme repository. Please make sure you look at the branch of your current version.
In my case, it is the 2.5 one that is installed (you can have this info in the Gemfile file), so I am looking at the 2.5-stable branch.

Our blog structure mainly relies on two folders:

  • _layouts: contains the layouts which are used in the Front Matter metadata of each markdown file.
  • _includes: contains snippets of HTML code that are used in layouts.

For instance, if we look at the code of the post layout, we see the following (shortened for comprehension).

<!-- _layouts/post.html -->
layout: default
  class="post h-entry"
  <header class="post-header">
    <h1 class="post-title p-name" itemprop="name headline">
      {{ page.title | escape }}

  <div class="post-content e-content" itemprop="articleBody">{{ content }}</div>
Enter fullscreen mode Exit fullscreen mode

There is a lot to comment on here.

The first thing we see is that the blog layout uses the default layout.
The way layout nesting works is that everything that you have below your Front Matter will be injected in the {{ content }} variable of its parent layout.

For instance when you write a blog post using this layout, its content is injected in the <div class="post-content e-content" itemprop="articleBody">{{ content }}</div> block.

We can also see the use of Front Matter metadata with the title of the post.
The title is displayed using the page variable, which contains all the variables defined in the Front Matter of a template.

These variables can be overridden by the children of the template. In this case, there is no title defined in the Front Matter of our template, it only makes sense for posts using this template.

Now, if we look at the default layout, this is what we see.

<!-- _layouts/default.html -->
<!DOCTYPE html>
<html lang="{{ page.lang | default: site.lang | default: 'en' }}">
  {% include head.html %}

    {% include header.html %}

    <main class="page-content" aria-label="Content">
      <div class="wrapper">{{ content }}</div>

    {% include footer.html %}
Enter fullscreen mode Exit fullscreen mode

The default layout represents the base structure of all our pages.
Besides the content variable where the child layout is injected, it uses several include to inject HTML code.

Let's now dive into them and start customizing our blog by adding a favicon.

Adding a favicon

Let's start gently by adding a favicon to our website. If you are familiar with HTML, you know that the favicon is defined in the head tag. For this theme, it is the _includes/head.html file that contains this tag.

You can override any file of your theme by putting it in your own project.
In this case, we can create our own _includes/head.html, copy the code from GitHub and modify it to add our favicon.

For my favicon, I generated one using a lion emoji for the sake of the exercise.

<!-- _includes/head.html -->
  <meta charset="utf-8" />
  <meta http-equiv="X-UA-Compatible" content="IE=edge" />
  <meta name="viewport" content="width=device-width, initial-scale=1" />
  {% seo %}
  <link rel="stylesheet" href="{{ '/assets/main.css' | relative_url }}" />
  {% feed_meta %} 
  {% if jekyll.environment == 'production' and site.google_analytics %} 
    {% include google-analytics.html %} 
  {% endif %}

    href="{{ '/apple-touch-icon.png' | relative_url }}"
    href="{{ '/favicon-32x32.png' | relative_url }}"
    href="{{ '/favicon-16x16.png' | relative_url }}"
Enter fullscreen mode Exit fullscreen mode

Modifying the header

The same way we overrode our head.html fille, we can override any file to customize your website as we want.

For instance, let's modify our header by adding our new logo.

To do so we need to add and modify the _includes/header.html file.

<!-- _includes/header.html --> 
<header class="site-header" role="banner">
  <div class="wrapper">
    {% assign default_paths = site.pages | map: "path" %} 
    {% assign page_paths = site.header_pages | default: default_paths %}
    <a class="site-title" rel="author" href="{{ '/' | relative_url }}">
      <img src="{{ 'favicon-32x32.png' | relative_url }}" />
      {{ site.title | escape }}
Enter fullscreen mode Exit fullscreen mode

Customizing our CSS

There are several ways to modify our CSS. As you can see in the head.html file, CSS is currently pulled from assets/main.css.
In the development file, it is actually a scss file that is built from the _sass directory.

An option to customize our css is to copy/paste the _sass directory and edit its files, the same we did for the head file.

Another possibility is to generate a new file that will be loaded after the theme css, so that the rules we put in it will override the default ones. This is the solution I will show you now.

First, let's create the assets/main.scss file with the following code.

// assets/main.scss

@import "minima";
@import "custom";
Enter fullscreen mode Exit fullscreen mode

Compared to the default file, I just added an import of the file custom. We can now create this file in the _sass folder and add some css.

// _sass/custom.scss
.site-title {
  color: orangered;
  &:visited {
    color: orangered;
Enter fullscreen mode Exit fullscreen mode

Here I modify the site title color to match our lion. My main point is to show you how you can do it, it is up to you to decide how you want to style your website.

Adding a featured image to our posts

Something you will see in almost every blog is a featured image displayed in the blog list and at the top of an article.

Unfortunately, this is not currently managed by Jekyll, so let's implement this feature ourselves.

This time we want to modify the blog layout directly. We can create our own version in _layouts/post.html.

What we are going to do is to check for a featured_image variable, and if it exists, we will display it on top of our title by adding the following snippet.

{% if page.featured_image %}
<div class="featured-image">
  <img src="{{ '/assets/' | append: page.featured_image | relative_url }}" />
{% endif %}
Enter fullscreen mode Exit fullscreen mode

Let's add a featured image to our last post. Put the image you want in your assets folder and add its name in the post metadata.

layout: post
title: "Write a Post"
date: 2021-06-31
categories: jekyll blogging
featured_image: featured-image.jpg
Enter fullscreen mode Exit fullscreen mode

We can then add some CSS to our custom.scss file to style it.

// _sass/custom.scss
.featured-image {
  margin-bottom: 50px;

  img {
    width: 100%;
    max-height: 250px;
    object-fit: cover;
Enter fullscreen mode Exit fullscreen mode

Here is the result.

Post With Image

Updating the home to display the featured image

Let's improve our home page.

First, copy the home.html in the _layout folder. Following the same principle as for the post layout, we can add our featured images.

<!-- _layout/home.html -->
layout: default 

<div class="home">
  {% if page.title %}
    <h1 class="page-heading">{{ page.title }}</h1>
  {% endif %} 
  {{ content }} 
  {% if site.posts.size > 0 %}
    <h2 class="post-list-heading">
      {{ page.list_title | default: "Posts" }}
    <ul class="post-list">
      {% for post in site.posts %}
          {% assign date_format = site.minima.date_format 
            | default: "%b %-d, %Y" %}
          <span class="post-meta">
            {{ | date: date_format }}
            <a class="post-link" href="{{ post.url | relative_url }}">
              {{ post.title | escape }}
          {% if site.show_excerpts %} 
            {{ post.excerpt }} {% endif %}
        {% if post.featured_image %}
        <div class="featured-image">
            src="{{ '/assets/' | append: post.featured_image | relative_url }}"
        {% endif %}
      {% endfor %}

    <p class="rss-subscribe">
      subscribe <a href="{{ '/feed.xml' | relative_url }}">via RSS</a>
  {% endif %}
Enter fullscreen mode Exit fullscreen mode

And update our custom.scss file.

// _sass/custom.scss
... .post-list > li {
  display: flex;
  flex-wrap: wrap-reverse;

  div:first-child {
    flex: 4 0 200px;
  .featured-image {
    flex: 1 0 200px;
    margin-bottom: 0;
Enter fullscreen mode Exit fullscreen mode

Here you are, you now have all the basics to create your personal blog at your own image.

You can find the code for this part here.

Our next step is now to add a commenting system to our blog.

Top comments (0)