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.
The problem
<!-- _layouts/default.html -->
<link href='assets/style.css' rel='stylesheet'>
The mess of relative paths
Let’s say you have an innocent URL in your layout like the one above. This is a relative path, not an absolute one that begins with /
. It resolves based on wherever it’s included from.
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… | Base | Final URL | |
---|---|---|---|
/index.html |
/ |
/assets/style.css |
Good ✓ |
/me.html |
/ |
/assets/style.css |
Good ✓ |
/about/profile.html |
/about |
/about/assets/style.css |
Wrong ✗ |
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.css |
Good ✓ |
user.github.io/project/ |
/assets/style.css |
Wrong ✗ |
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 %}
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>