Relative paths in Jekyll

Jekyll is a great static site tool. If you're using GitHub Pages, it comes with it for free, making it a very useful tool for any public blog or website. It comes, though, with one common problem that I've yet to come across a good solution for: relative paths.

Next: Why are relative paths a problem?

The problem

The mess of relative paths

Let's say you have an innocent URL in your layout like the one below. This is a relative path, not an absolute one that begins with /. It resolves based on wherever it's included from.

<!-- _layouts/default.html -->
<link href="assets/style.css" rel="stylesheet" />

This works well in pages of your site placed in the root directory. Once you path one level deep though, you'll encounter problems.

From this page...BaseFinal URLResult
/index.html//assets/style.cssGood ✓
/me.html//assets/style.cssGood ✓
/about/profile.html/about/about/assets/style.cssWrong ✗
Next: How do we usually work around them?

A naive workaround

One workaround is to use absolute paths by adding a / in the beginning.

<link href="/assets/style.css" rel="stylesheet" /> ^

Why absolute URLs suck

This works great for sites that live on its own domain. When your site will be hosted in a sub-directory (such as the case with GitHub Project Pages), this absolute path will not resolve to /project/assets/style.css as you probably would have intended.

If your site is in...It resolves to...
user.github.io//assets/style.cssGood ✓
user.github.io/project//assets/style.cssWrong ✗
Next: Let's look at a better workaround.

A better workaround

This snippet below automatically determines the relative base and stores it in the variable base. Place it in your partials path, and include the partial in your layouts.

<!-- _includes/base.html -->
{% assign base = ''
%}{% assign depth = page.url | split: '/' | size | minus: 1
%}{% if depth <= 1
%}{% assign base = '.'
%}{% elsif depth == 2
%}{% assign base = '..'
%}{% elsif depth == 3
%}{% assign base = '../..'
%}{% elsif depth == 4
%}{% assign base = '../../..'
%}{% endif
%}
Tip: You can also collapse this into one line.

Use it as a prefix

You can then use it as a prefix to URLs, like the examples below. You don't need to include it all the time—just include it once in your layouts and it will be available everywhere.

{% include base.html %}
<link href="{{base}}/assets/style.css" rel="stylesheet" />
<a href="{{ base }}">Back to home</a>
<a href="{{ base }}/about.html">About me</a>
<a href="{{ base }}{{ post.url }}">Read "{{ post.title }}"</a>