Updating a 6 year old Jekyll & Bootstrap website
By no stretch of imagination am I a frontend person. Graphic design is not my passion. I even got the colour blindness perk. I do like this little website I’ve written over the years and I kind of want it to look nice. And while the design I had created a few years ago still works, it’s also dependent on an outdated version of Jekyll, and it has a few technical issues. So please, follow a long, as a DevOps engineer tries to explain how to make a nice-looking website.
My website is built on Bootstrap. Bootstrap is very nice because it makes it much easier to get an acceptable design. It does use a bit more javascript than I’d like to The former is nice because it does most of the design for me, but the latter is open for debate. Also, the colour scheme could use some work.
So in no particular order, let’s see what I actually discovered along the way and what things turned out to be useful.
Updating Bootstrap 4.6 to 5.2
Bootstrap has both changed a lot and not changed at all, which made the upgrade somewhat tedious. You can read the Bootstrap changelog for more details. For the most the most part, things were alright. A non-exhaustive list of things that bit me is
-
The official Sass compiler was changed from
libsass
to Dart Sass. You can still compile Bootstrap with libsass, but now you will notice the bugs in the compiler that Bootstrap no longer works around. For example,libsass
handles negative numbers incorrectly causing them to sometimes not be equal to themselves. It only causes minor issues like the pagination number boxes being rounded when they shouldn’t, so if you want to avoid Dart you can still go for it. -
Many CSS classes have moved from outer element to the inner one. For example: items in the navigation bar in 4.6 would apply the
.active
class to the outer.nav-item
element, but Bootstrap 5 requires you to apply it to the.nav-link
element instead.
Actually putting this all together is not too hard. Most things actually translated quite naturally. As part of updating the styling, I found that it was easier to remove my custom components and replace them with modified Bootstrap components.
Speaking of modifications: previously this site used the Superhero Bootstrap theme which worked
well enough but requires a bunch of scaffolding code and doesn’t really integrate into Bootrap, but
rather forces itself through. This has funny results like $blue
not being blue at all, though most
of the time it results in redundant code. Theming is now completely done with variable overrides,
and just 30 lines of overrides (including comments and whitespace) is enough to somewhat
consistently override default colours and “work around” assumptions of contrast between them.
The basics for this theming can be as simple as the snippet below. The only hard thing about it was choosing a proper color scheme. I found Coolors helpful to compensate for my less-than-stellar design skills. The linked colour scheme is not coincidentally a colour scheme I liked but didn’t actually go for. By all means use it.
1
2
3
4
5
6
7
8
9
10
@import "bootstrap/functions";
// Don't actually use these colors
$body-bg: purple;
$body-color: azure;
$primary: ivory;
$secondary: navy;
$dark: thistle;
// Import the rest of Bootstrap
Moving the build to Github Actions
While I was working on the the big refactor, Github first teased, then finally announced a solution to the much requested Jekyll 4 support in Github Pages. Seeing as I’ve been waiting for this feature ever since Jekyll came out1 I wasn’t really expecting anything, but it is now possible to manually build your site using Github Actions. That means that we can now have full control over the build process and can do anything we want.
The example workflows Github has provided are actually very simple and you can
mostly drop them in. I had one issue with them, which could be resolved by
removing the --baseurl
override, but this has since been resolved. Great issue response, guys!
It turns out that I don’t really want all that much. The only immediate thorn in my side that I
could fix was to update the default Sass compiler. Jekyll ships with sassc
by default, which
doesn’t handle negative numbers properly and causes a few miscompilations with Bootstrap. Luckily,
it also supports using the reference Dart Sass compiler. All that’s needed is adding the
sass-embedded
gem and overriding the compiler preference:
1
2
3
# _config.yml
sass:
implementation: sass-embedded
Replacing the math renderer
My posts occasionally contain some maths and because I have been properly taught at some point in my life, I like to typeset that in .2 Regrettably, support for Latex in HTML is still not really a thing so you need to render it one way or another.
Kramdown by default comes with “MathJax support” but that mostly means that instances of $$some
maths$$
are replaced with \(some maths\)
. No actual rendering is done while building the site. To
add the actual rendering, you are required to load quite some additional JavaScript files, which
then in turn marks up the text and loads some more fonts for the true Latex look and feel. This is
kind of slow and changes the page layout, so you get that much maligned layout shift effect.
You are familiar with this effect, but you might not know it was called like that. For a refresher, try clicking the green button in the demo below.
All in all, I didn’t really like what MathJax did to the site. Luckily, thanks to moving to Github Actions, I could now add my own dependencies to the build. Which brings me to KaTeX. KaTeX is also a JavaScript-based TeX renderer, but unlike MathJax, it can render the math server-side. The final page then only requires some CSS and webfonts to render correctly. The webfonts are technically even optional, though everything looks slightly off without them.
There is an official plugin for Kramdown that makes it use KaTex. You can simply
add the gem to your build, and enable with by adding the following to your _config.yml
:
1
2
kramdown:
math: katex
Unfortunately that doesn’t include the KaTeX CSS yet, so we still need to add that to the site. The recommended method appears to be to use the jsDelivr CDN, but public CDNs aren’t that great of an idea so I didn’t want to do that. Instead I wrote my own Jekyll plugin to automatically copy the relevant files from the KaTeX gem. This plugin can probably be done better by someone who actually knows how to write Ruby, but it gets the job done:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
require 'katex'
require 'find'
require 'pathname'
module Jekyll
module KatexBundle
class KatexResource < Jekyll::StaticFile
def destination(dest)
File.join(dest, 'assets', 'katex', @dir, @name)
end
end
class Generator < Jekyll::Generator
def generate(site)
@site = site
@site.static_files << css_file
@site.static_files.concat font_files
end
private
def css_file()
path = Pathname.new File.join(Katex.gem_path, 'vendor', 'katex', 'stylesheets', 'katex.css')
source = path.dirname()
file = path.basename()
KatexResource.new @site, source, '', file
end
def font_files()
assets_dir = File.join(Katex.gem_path, 'vendor', 'katex')
fonts_dir = File.join(assets_dir, 'fonts')
fonts = []
Find.find(fonts_dir).each do |path|
next if File.directory?(path)
path = path.sub(fonts_dir, 'fonts')
dir = File.dirname(path)
file = File.basename(path)
static_file = KatexResource.new(@site, assets_dir, dir, file)
fonts << static_file
end
fonts
end
end
end
end
In the future I may decide to release this as a standalone plugin. The KaTeX gem also appears to support sprockets, so maybe I’ll try to get that to work instead. The Jekyll Assets plugin looks promising.
Moving on
The main update is now a few months behind me and things work well enough. Now back to non-radical, incremental change. Or maybe I’ll rewrite it in Cobalt or Zola in a few months. Who knows? For now, the site can look like this for a while.