This lesson is being piloted (Beta version)

Page Layouts

Overview

Teaching: 30 min
Exercises: 25 min
Questions
  • How can I design the layout for all pages on my site?

  • Where can I find pre-built themes for my site?

  • How can I create new layouts based on those I already have?

Objectives
  • Apply a template layout to a page

  • Find and implement pre-existing themes to determine the style of a site

  • Create new page templates that inherit from existing layouts

Elements that will appear on every page across our website, like the banner image we included in our pages in the previous section, form part of the structure of the page: unlike the content specific to each page, these structural elements do not change from page to page. As such, although the include tags reduce the pain endured when adjusting that repeated content, it is not good practice to include the same content over and over again. This structure can instead be defined within the layout of the pages of the site.

Common elements found in a layout are logos, banners, navigation menus, footer content such as copyright and licensing information: material often found at the very top or very bottom of a webpage.

Defining a Layout

Jekyll layouts are defined as HTML files in a special _layouts folder. We will want our navigational links to appear on every page of our site so, instead of using an include tag on each page individually, we should add it to the layout used for each page. Just like our site’s pages, layouts can include blocks defined in other files, but the catch is that these must also be HTML (remember the last exercise when we asked you to create a footer in HTML instead of Markdown?).

We will now define a new page layout called default, which we will save in a file _layouts/default.html. Having defined our navigational links in a separate file, we will start with a layout file that only includes these links:

{% include navigation.html %}

You have just defined the first layout for pages on your site. Congratulations!

Add layout: default to the YAML front matter of index.md to apply this layout to your site’s home page, then do the same in the front matter of about.md. When you reload your site’s homepage (or any page you applied the layout to), you will see that there is good news and bad news: The good news: the navigation links are there again; the bad: all the other page content has disappeared!

The page content is missing because we haven’t yet told Jekyll where to put it. To do that we need to add the special content variable into the layout file:

{% include navigation.html %}

{{ content }}

We can use the content variable to tell Jekyll where it should place all the content defined in the Markdown of the page within this layout. If we make the change shown in the example above to _layouts/default.html and reload our site’s homepage, we now see the page content has returned but we have two more problems: the styling of our pages has changed (for the worse) and the navigational links appear twice!

A page displaying the navigation section twice.

The duplication is happening because the {% include navigation.html %} tag is still present in index.md.

Exercise: Cleaning Up

Remove the include tag for navigation links from all the pages of your site (e.g. about.md), and set every page to use the default layout.

Now that we have cleaned the duplicated navigation links, we may want to add another element to our layout. In a similar manner to the navigation links appearing on every page, we may want a common footer to appear too.

Exercise: Expanding the Layout

Expand the layout we have just created to include a footer element at the bottom defined in _includes/footer.html so that it appears at the end of each page that uses this layout.

Solution

Include the footer file in the _layouts/default.html layout file as follows:

{% include navigation.html %}

{{ content }}

{% include footer.html %}

Remove all references to footer.html from pages as they will now be included via the layout. Check that this works by reloading any of the pages that use the default layout. You should see a footer at the bottom of the page.

HTML Structure, Metadata and a Default Layout

Before we defined a layout for our pages, Jekyll used a default theme to style the site. That default has been overwritten now that we applied a layout file to our site and that means, if we want to use our own customised layouts, we will need to start telling the browser in more detail how we would like our pages to be styled. There is still more to learn about page layouts, so we will come back to this issue of styling at the end of the episode.

You might recall from the introduction to this tutorial, that a valid HTML page consists of more than only the content we want to display. We haven’t written these extra elements (<html>, <head>, <meta>, etc) in our layout file: but there are some advantages to defining these yourself: these invisible elements of a web page describe metadata about the page, which can be used by Internet search engines to better understand what the page is about and who it is for. This information is factored in when the search engine indexes the page, and subsequently makes it more findable for your target audience. (This is one consideration in the much larger field of Search Engine Optimisation.)

For example, to make the browser automatically adjust the way your pages are shown on different displays/devices, you could include the metadata element <meta name="viewport" content="width=device-width, initial-scale=1.0"> inside the <head> of your pages. (Read this W3Schools page to learn more.)

It is common practice to define the structural HTML elements of your site’s pages inside a _layouts/default.html file. This file defines the bare minimum layout your pages should have.

Exercise: Adding HTML Structural Elements to Default Layout

Modify the default layout file _layouts/default.html with the following content:

<!doctype html>
<html lang="en">
  <head>
    <meta charset="utf-8">
    <title>{{ page.title }}</title>
  </head>
  <body>
    {% include navigation.html %}
    <h1>{{ page.title }}</h1>
    <section>
      {{ content }}
    </section>
    {% include footer.html %}
  </body>
</html>

What do you notice has changed about the pages that use this layout?

Solution

After updating the layout, each page includes the page title displayed twice.

Note that we have also included some additional HTML elements in our default layout - the display of the page title as level-one heading and wrapping the main page content within <section> and </section> tags.

We have not been defining the title in the front matter of each of our pages, and Jekyll is guessing the page title based on the first heading it finds. The layout displays the page title at the top of the page, above the page content, which also contains the page title. As a result, the title ends up being displayed twice. To fix this problem, we must remove the first-level headings from the Markdown content of our pages and instead define the title in the page front matter. For example, about.md should look like this after the change:

---
layout: default
title: About
---

## Project

Building Websites with Jekyll & GitHub Pages.

## Funders

We gratefully acknowledge funding from the XYZ Founding Council, under grant number 'abc'.

## Cite us

You can cite the project as:

>    *The Carpentries 2019 Annual Report. Zenodo. https://doi.org/10.5281/zenodo.3840372*

Layout Inheritance

To prevent the duplication of all this “invisible” HTML across all the layouts we define for a site, Jekyll allows for layouts to be based on other layouts, which can be based on other layouts, and so on. This is referred to as layout inheritance, and is refreshingly easy to use.

For example, let’s say we want to create a slightly different layout for our home page and include a banner image just below navigation links to make it pretty. To do so, we first need to upload a banner image to our repository and create a HTML snippet _includes/banner.html to include the banner image:

  1. To add a pre-made banner image, click “Create new file” under the “Add file” dropdown on your repository homepage,
  2. In the “Name your file…” box, type images/. The folder name should be automatically inserted in the path displayed next to this box for naming the file. It is good practice to store all image files in a common folder.
  3. You can then leave the file blank and name it .gitkeep. When you commit the changes, the images folder will have been added to your repository. We will be uploading our banner image to this folder in a moment. Unfortunately GitHub does not provide a way to create a new folder while uploading existing files, only while creating new ones. When making these blank files, which exist only to allow the existence of their parent repository, it is traditional to call them .gitkeep.
  4. Now download this banner image that we will add to our pages save it with the name site_banner.png and upload the file to your newly-created images folder on GitHub: you can do this by navigating into the folder and choosing “Upload files” from the “Add file” dropdown you used before.

Now that the banner image is available in our site repository, add the HTML file _includes/banner.html with the following content:

<img src="./images/site_banner.png" alt="Group Website banner">

Next, we need to create a new layout file _layouts/home.html and then set it to inherit from the default layout by adding YAML front matter specifying the layout (of the layout file) to be default.

---
layout: default
---

We can then add any extentions to the new layout home.html that will be applied on top of the default layout. This is what _layouts/home.html file should look like:

---
layout: default
---

{% include banner.html %}

{{ content }}

Defining a Layout for a Layout

Note how layouts can be applied not only to regular pages but also to other layouts, effectively making a layout inherit from another layout.

Finally, we can now update the layout of the home page to be home instead of default by modifying the YAML front matter. If you reload the home page now, you should now see that it has all of the structure provided in default layout as well as the banner image included from the home layout.

Home page with inherited layout

The purpose of this approach, defining the core structure that will be common to every page across the site in a default layout, then basing more specific layouts on this foundation, is to keep duplication to a minimum within our repository. Whenever we want to update something about the styling or structure of our site, we should only need to make that change in a single file and let it propagate to all the relevant pages.

In the previous section, we recommended that you include a file of references for the links on your site. Unfortunately, you cannot add this {% include links.md %} tag to the default layout of your site to prevent you from needing to add it at the bottom of every page. This is a result of the order of Jekyll’s rendering process, which constructs the HTML of the page content in isolation before constructing the HTML of the relevant layout(s) and nesting it inside. If the link references are included in the layout rather than the content, those references will not be available while the content is converted to HTML and the links will not render correctly. It is annoying to have to remember to add {% include links.md %} to the end of every page’s Markdown, but less annoying than having to manually edit the same link reference in multiple locations throughout the site.

Using Pre-Existing Layouts From a Theme

We have now seen how to create pages, re-use content across them, and define layouts, and you may be coming to understand that it requires a lot of work to build a website from the ground up. This is not a task we recommend you undertake lightly!

Instead, an alternative is to base your site on one of the many pre-existing themes for Jekyll. Many of these themes are free and open source and, as long as you follow the terms of the license (e.g. remember to give due credit to the original - check the full terms for details), can be adapted/customised to suit your purposes. You can browse a list of Jekyll themes on jekyllthemes.io.

These themes can be elaborate and quite complicated. We hope that the knowledge of Jekyll that you have gained from following this lesson will help you understand how they work and determine what you need to change and where, to make the customisations you need for your site. Reusing pre-existing themes designed by professional web designers helps you focus more on the content of your site, which you can write using more user-friendly and human-readable Markdown.

Key Points

  • Files in the _layouts/ directory can be used as page templates

  • The structure of a page is determined by the layout field in the page front matter

  • You can find many pre-existing themes for sites on the Internet

  • You can avoid duplicated effort by basing new layouts on previous ones