A full-blown CMS is rarely necessary. Sometimes, you only need to create a light, static website … but you have just enough pages to make the process of copying template files and making cross-site markup changes a chore. Today, I’ll demonstrate a simple solution—Jekyll—that will make creating small websites a breeze.
Step 0: Meeting Jekyll
Jekyll is a simple, blog aware, static site generator.
Jekyll is a simple, blog aware, static site generator. That’s what the site says. But, what exactly does this mean? A static site generator is a program that takes a set of files and generates your site with them. As you’ll see, we’ll be able to use a set of templates, create the content files separately, and then use Jekyll to generate our site. The “blog aware” part means that we could use this to create a blog, or any website that has a series of post-like entries (such as a portfolio). Let’s give it a try!
Step 1: Installing Jekyll
Refer here for more information on Ruby Gems.
We’ll begin by installing Jekyll; it’s a Ruby gem, so doing so should be pretty straightforward.
gem install jekyll # use `sudo` if your setup requires it
Yep: it’s that easy. There are a few more pieces we could install if we are planning on doing a more complex set-up, however, since we’re not, this will do the trick.
Step 2: Creating our First Template
Every file or folder that does not begin with an underscore will be copied to the generated site.
Next, let’s set up the folders for Jekyll. Create a folder, called example-app
for this tutorial; we’ll be creating a little portfolio site for, say, a photographer. This is a great example of where Jekyll shines: it’s a small site that won’t be updated too frequently, but is large enough to the point that you don’t want to open every page when you need to make a markup change.
Inside example-app
, create a folder called _layouts
. Notice the underscore at the beginning of this folder: any folder or file that begin with an underscore will not be part of the site that Jekyll generates. If they have a name that Jekyll recognizes (such as _config.yml
or _layouts
), their contents will be used in the generation of the site, but the files themselves won’t show up in the site. Remember this: every file or folder that does not begin with an underscore will be copied to the generated site (which, by the way, defaults to the _site
sub-folder).
So, let’s create a layout. We’ll start with a general site layout that includes all the “chrome” for our site. Create a new file, called default.html
inside the _layouts
folder (the name doesn’t matter), and add the following code to it:
<!DOCTYPE html> <html> <head> <meta charset=utf-8 /> <title> {% if page.title %} {{ page.title }} | {% endif %} John Doe, Photographer </title> <link rel="stylesheet" href="/css/styles.css" /> </head> <body> <div id="main"> <header> <h1> John Doe Photograghy </h1> <header> <nav role="navigation"> <ul> <li><a href="/">Home</a></li> <li><a href="/portfolio/">Portfolio</a></li> <li><a href="/about">About</a></li> <li><a href="/contact">Contact</a></li> </ul> </nav> {{ content }} <footer> <p>@copy; John Doe Photography 2011 | All Rights Reserved. </p> </footer> </div> </body> </html>
A couple of things here to keep in mind...
Firstly, Jekyll uses the Liquid template system (by default). This means, anything you can do with Liquid, you can do in a template in Jekyll. For example, in the <title>
tag, we’re using both types of Liquid markup: output markup and tag markup. Output markup may output text (if the variable referenced exists), while tag markup doesn’t. Output markup is delimited by double curly-braces, while tag markup is delimited by a the curly brace / percent sign duo.
The next thing to notice above is what is inside the Liquid tags: things like page.title
and content
. These are variables provided by Jekyll; you can see the list of available template data in the docs. We can also create custom template data, as we’ll review shortly.
Lastly, notice the CSS we’re linking to: create a css
folder in the root of your project and throw this bit of styling into a style.css
file:
body { font: 16px/1.5 verdana, helvetica-neue, helvetica, arial, san-serif; background: black; color: #ececec; padding: 0; margin: 0; } ul { margin: 0; padding: 0; } a { color: #ccc; text-decoration: none; } a:hover { color: #ececec; text-decoration: underline; } #main { width: 960px; margin: 0 auto; background: rgba(255, 255, 255, 0.4); } header { padding: 0 10px; overflow: hidden; } h1 { margin: 0; } nav ul, ul.entries { list-style-type: none; } nav li a { float: left; margin: 5px; } .content { padding: 10px; } ul.entries li { position: relative; margin: 20px auto; padding: 20px; background: #ececec; width: 600px; } ul.entries img { width: 600px; } ul.entries li h3 { position: absolute; bottom: -18px; left: 17px; font-size: 2em; } ul.entries a { color: #ececec; } ul.entries a:hover { color: #fff; } footer { font-size: 0.65em; text-align: center; }
Also, create an img
folder and add an image, named banner.jpg
; we’ll be using it shortly. Any image will do; just crop it to 960px
by 300px;
.
You might be wondering why we're using the if
statement above if the page.title
variable just won’t display if it exists? Well, if it does exists, I want to include the vertical bar after it; another way to write that would be like this:
{{ page.title }}{% if page.title %} | {% endif %}
So, how we do use this template? Well, we need to create a page that will use this template. In the root directory of our project, create an index.html
file. Here’s the content:
--- layout: default --- <section role="banner"> <img src="/img/banner.jpg" /> </section> <section class="content"> <p> Welcome to John Doe Photography! Please, check out my <a href="/portfolio/">Portfolio</a> to see my work. </p> </section>
Here’s the content of our index.html
file. Notice what’s at the top of the file: Jekyll calls this YAML front matter. Any file (that doesn’t start with an underscore) that has YAML front matter will be generated by Jekyll before being put in the _site
folder (if it has no underscore or YFM, then it will just be copied _site
). In this case, the YAML front matter just tells Jekyll what template we want it to use.
Now, open a terminal, cd
into your project directory, and run jekyll
. You should see something like this:
WARNING: Could not read configuration. Using defaults (and options). No such file or directory - /Users/andrew/Desktop/example-app/_config.yml Building site: /Users/andrew/Desktop/example-app -> /Users/andrew/Desktop/example-app/_site Successfully generated site: /Users/andrew/Desktop/example-app -> /Users/andrew/Desktop/example-app/_site
Ignore the warning; we’ll come to that shortly. For now, you can see that the site has been built in a freshly-created _site
directory. If you open the _site/index.html
file in your browser of choice, you should see … a failure. The problem is that our paths (urls and stylesheet) begin with a forward slash. This means we can’t just view them as files, we need to view them on a server. Sure, you could go start up W/MAMP, but why take the trouble? Jekyll has a built in server. So, run jekyll --server
, and go to localhost:4000 to see something like image below:
If the image above isn’t enough, look at the code of _site/index.html
. You’ll see that the template we specified was blended with the content we provided and—voila!—we have our page.
I want to remind you that it’s the YAML front matter that makes this magic happen; if a file doesn’t start with three dashes, one or more lines of properties, and another line of three dashes, the file will just be copied to the _site
folder, no generation taking place.
Step 3: Creating a Portfolio Template
Now that we’re comfortable with the basics, let’s create a portfolio for our fictional photographer. Remember how I noted that Jekyll is “blog aware”? Well, we’re going to use this blog-awareness feature to our advantage: instead of posts, we’ll have portfolio entries.
Posts belong in a folder, called _posts
, so create that now. The file name pattern for posts must be specific as well: year-month-day-title.ext
. Posts — well, any file in your Jekyll site, really — can be either Markdown or HTML.
So let’s make a few posts: remember, these will actually be entries in our portfolio:
_posts/2010-03-04-bikes.md
--- layout: portfolio_entry image: /img/bikes.jpg title: Bikes, Black and White --- Bikes are used by almost everyone in downtown Amsterdam. These ones are chained to a bike rack.
_posts/2010-10-01-wing.md
--- layout: portfolio_entry title: Wing and a Prayer image: /img/wing.jpg --- The wing of the AirBus I rode to England.
_posts/2011-06-05-bridge.md
--- layout: portfolio_entry title: Stone Bridge image: /img/bridge.jpg --- An old stone bridge in London.
_posts/2011-07-09-road.md
--- layout: portfolio_entry title: Road and Curb image: /img/road.jpg --- Bike lanes here are terribly thin.
Pretty simple, eh? Notice how we’re creating a custom YAML front matter field: image
. This is the URL to the image for that entry. Sure, we could build the whole entry HTML here in this file, but what if we want to change that? We’d have to return and change it in every entry. This way, we can instead use our portfolio_entry
template to render them. What’s that template look like? It’s pretty simple too:
_layouts/portfolio_entry.html
--- layout: default --- <h2 class="content">{{page.title}}</h2> <img src="{{ page.image }}" /> {{ content }}
If you looked at the template data page, you’ll know that any custom front matter we add will be available under page
; so, here, we can access page.image
. We’re also using page.title
and content
(everything after the last three-dash line).
I should mention here that, while the post title
is supposed to be available on the post
object, I’ve only been able to get it to work on the page
object. Whatever works!
Also, notice that we have this template using our default
layout. You can nest templates like that, and make your job even easier.
This gives us our entry (post) pages, but what about the main portfolio page? When writing our navigation in our default layout, I noted that we want it as /portfolio/
. So, create a folder, called portfolio
in the root directory, and open an index.html
file within it.
--- layout: default title: Portfolio --- <section class="content"> <h2>Portfolio</h2> <p>Check out my images below!</p> </section> <ul class="entries"> {% for post in site.posts %} <li> <a href="{{ post.url }}"> <img src="{{ post.image }}" /> <h3>{{ post.title }}</h3> </a> </li> {% endfor %} </ul>
This is our most complicated piece yet. Remember, this isn’t a template: it’s a “normal” file, but it can still include Liquid tags. We start by setting layout
to default
, and title
to “Portfolio.”
Notice that, in the HTML, we have a Liquid for-in
loop. We retrieve all the posts with sites.posts
; then, we loop over those posts with for post in site.posts
/ endfor
. If you’ve worked with WordPress, or any other blogging system, you should be familiar with the concept of a loop
. That’s all this is! Inside, as you can see, we can get the standard properties, as well as any front matter we defined (like image
).
Now if we run jekyll --server
to re-generate the site and start the server, localhost:4000/portfolio/ should show this:
And here’s an entry page:
Great! You’ve created a portfolio. I’m sure you see, as well, how this works for a blog. Let’s now move on to look at some configuration options for Jekyll.
Step 4: Writing a Config File
There’s a plethora of options for Jekyll. It’s great that all of them have really sensible defaults, but if you want to change them, it’s not hard at all.
There are two ways to set options.
- First, when you run the program on the command line, you can pass parameters. We’ve already seen the
--server
parameter, which starts a server after generating the site. - A different way, and the way we’ll use here, is in a config file, called
_config.yml
; this is a YAML file, so each line isa key: value
pair, just like in the YAML front matter. Jekyll will look for this file before generating site.
So, make an _config.yml
file, and let’s check out some of the most common options.
For a complete list of options, review the configuration documentation.
-
auto
: Addingauto: true
to your config file will keep Jekyll running, watching your project folder for changes and regenerating the site on the fly. -
source
: If your source files are in a different directory than the one you’re running Jekyll from, you’ll want to set that directory with thesource
property. -
destination
: By default, the destination for your generated site is./_site
. If you’d like something different, set it here. -
permalink
: The permalink is the path to your posts. By default, that’s/year/month/day/title.html
. However, you can customize that if you want. Among others, you can use the variables:year
,:month
,:day
,:title
, and:categories
.:categories
comes from the front matter; all the others come from the post file name. Then, you can setpermalink
to things like/:year/:month/:title/
or/:categories/:title.html
. Bonus tip: if you have apermalink
property in the post front matter, it will override the site-wide default. -
exclude
: Like I said above, Jekyll won’t generate files in directories starting with an underscore. But, if you have folders that you want it to ignore, but that don’t start with an underscore, you can do it withexclude
in your config file.
Step 5: Deploying the Site
So, let’s say you’ve created the site, and want to set it free, out on the world wide web. How do you do that?
There are several ways to accomplish this. Of course, if it’s a small site that you won’t be updating too often, then simply FTP it up to your server; this might be your only option, if you’re using shared hosting.
If you’ve got a VPS or dedicated hosting setup, you can run more automatically. Check out the deployment documentation for a list of good ideas. If you aren’t sure what to do, try following the directions for using the git post-receive hook; I’ve tried that, and it’s pretty cool.
Step 6: Taking it Further
This is just the tip of Jekyll.
- There’s a plugin architecture that let’s you modify how your content is generated.
- There’s more you can do with Liquid and some Liquid extensions that Jekyll adds.
- There’s a lot of template data that we didn’t talk about. Check it out and see what you can do!
Conclusion
Well, that’s your introduction to Jekyll - the simple, blog aware, static site generator. The next time you’re building a brochure-style, business-card-y, micro-portfolio site, think you’ll give Jekyll a try? Let me know in the comments and thank you so much for reading!
Comments