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.

Before all changes

The website before I got started on upgrading

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 LaTeX\LaTeX.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.

Website after the update

How it looks after applying all of this

  1. I looked up when I first got a notification from being subscribed and it apparently was September 24th, 2019, ↩︎

  2. It’s entirely possible that this is just because I’ve been forced to use it but you can’t deny that the result looks beautiful. ↩︎