Page Layouts
Last updated on 2022-11-15 | Edit this page
Estimated time: 55 minutes
Overview
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:
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:
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!
The duplication is happening because the
{% raw %}{% include navigation.html %}{% endraw %}
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.
Include the footer file in the _layouts/default.html
layout file as follows:
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][seo-wikipedia].)
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][w3-viewport].)
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:
HTML
{% raw %}<!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>{% endraw %}
What do you notice has changed about the pages that use this layout?
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:
MARKDOWN
---
layout: default
title: About
---
## Project
{{ site.description }}
## 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:
- To add a pre-made banner image, click “Create new file” under the “Add file” dropdown on your repository homepage,
- 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. - You can then leave the file blank and name it
.gitkeep
. When you commit the changes, theimages
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
. - Now [download this banner image that we will add to our
pages][banner-image] save it with the name
site_banner.png
and upload the file to your newly-createdimages
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:
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
.
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:
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.
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.
We Can’t Include Link References in the Layout
In the previous section, we
recommended that you include
a file of references for
the links on your site. Unfortunately, you cannot add this
{% raw %}{% include links.md %}{% endraw %}
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][jekyll-rendering], 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
{% raw %}{% include links.md %}{% endraw %}
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][jekyllthemes].
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