Build a Ready-To-Use Jekyll Setup — Part 3: Dynamic Navigation Menu
This article is the third part of a series on how to build a Jekyll setup that can be used to develop multi-page websites with static contents in two languages and which are served by an Apache HTTP Server. In the second part we made the website bilingual. However, the navigation menu must be adjusted to work properly.
In This Part
We will add a navigation bar which is dynamically generated during build time, based on a pre-defined list of items. The advantage of a pre-defined list is that we can easily determine just a subset of all available pages to be included, as well as the order of the navigation items and a submenu.
It is recommended that you follow Part 1 and Part 2 of this guide before proceeding. Alternatively you can download the resulting source code from Part 2 on GitHub, as we will use it as a starting point here.
After following Part 1 and 2 of this guide, the current folder structure looks as follows:
We begin this part by adding additional pages to our collections.
_de/ directory create the following files with the corresponding content. The Front Matter attributes follow the same structure as described in the second part of this guide.
_en/ directory create the corresponding counterparts with the respective contents.
Note that each new file in the
_en/ collection has a corresponding counterpart in the
_de/ collection with the same
name attribute as described in part two of this guide.
We want a solution that makes it easy to define the structure of the navigation menu. The solution should also give us the opportunity to define a submenu, to exclude specific pages from the menu as well as specifying the order of the navigation menu.
A comfortable way of doing this is by defining the structure of the navigation menu in some kind of list. We can use a YAML file for this. By default, Jekyll provides an optional folder,
_data/, to host YAML and other file formats which will be accessible during the build process without further configuration.
We will make use of this feature and create a
_data folder in the project root directory. Inside the folder create a new YAML file
navigation.yml with the following content:
This file defines the structure of the navigation menu. In line 1 we define a name,
main, under which the German and the English menus will be available (you can choose a different name if you want). Wrapping the configuration for the navigation menu this way gives us the opportunity to configure multiple navigation menus in the same file.
main we create two lists,
en. Their naming must follow the definition of the collections in
_config.yml, i.e. de and en. Otherwise, the next step won’t work.
The items in
en will define the structure for the German and the English navigation menu. Every item within one of the two lists will represent a navigation item of the respective language. The order of the items is important since the order of the navigation items in the rendered HTML document will be the same.
Each item itself consists of a
label and a
url variable. The value of the
label will be used as the label of the navigation item and can be freely selected. The value of the
url will be used to build the reference to the related file. It therefore must match with respective file name within the corresponding collection, plus a leading forward slash (e.g.
/doors.html when referencing
doors.html from the English collection
That way we can simply add to or remove pages from the navigation menu, as well as specifying the order of the navigation items.
If we want an item to host a submenu, we can add a third attribute
submenu which in turn holds a list of items containing a
label and a
url, similar as before.
We can now bring everything together in the
nav.html file — our HTML template for the navigation menu. What we want is to generate an unordered list
<ul> of items based on the pre-defined structure in
navigation.yml. When an item contains a submenu, we want the submenu to be an unordered list within the current list
<li> element, too.
nav.html as following:
The two links from the previous part are removed. Instead we loop over the list of navigation items as defined in
navigation.yml, which corresponds to the language of the current page. We do that with a for-loop in line 3.
site.data.navigation.main[page.lang] can be interpreted as following:
site is a Jekyll variable that gives us access to the
_data/ folder and the
navigaton.yml file. In
navigation.yml we access the
main variable which we used to wrap the German and the English navigation menu. We then use the language code defined in the Front Matter of the current page,
page.lang, to access the list of menu items that corresponds to the current language.
For each item of the selected list we create an anchor element
<a> within a list element
<li> (line 4 to 7). The value of the
href attribute is build by concatenating the
baseurl from the
_config.yml, the language code of the current page (
page.lang) and the file name of the current item as defined in the
url attribute within
navigation.yml. The label is also taken from
label attribute of the current item.
If any item contains a submenu (checked in line 9) a second unordered list is generated by looping the nested list of submenu items, similar as before.
In addition, we add an additional CSS class for the item that contains a submenu in order to give it a different styling or behavior if needed (line 4).
We now have the following folder structure:
bundle exec jekyll serve in your terminal now builds and serves the website under http://127.0.0.1:4000.
The navigation is now dynamically generated according our pre-defined list in
navigation.yml and works as expected. Regardless on which page the language is toggled, the same page is loaded in the alternative language.
GitHub: Jekyll setup - Part 3
In the Next Part
We build a configuration file for a virtual host of an Apache HTTP Server in order to serve the website in the language that corresponds to the language set in the Accept-Language header field of the HTTP request.