A few months ago I began tinkering with the blog index, almost redesigning it from scratch.

Here’s a comparison of the changes:

screenshot of old blog homepage

Old site

So much has been redone that I can’t break it down into a simple changelog.

Interactive elements

I added a random post button, and a search bar. Let’s talk about the search.

It uses the Simple Jekyll Search library, and another file called call_search.js which does nothing more than call the search function and pass some options.

  searchInput: document.getElementById('searchbox'),
  resultsContainer: document.getElementById('results-container'),
  json: 'post_list.json',
  searchResultTemplate: '<li><a href="{url}">{title}</a></li>',
  noResultsText: 'No results found',
  limit: 10,
  fuzzy: true

That short bit of code should probably just be integrated into the main js file, but I tried including it and it didn’t work, so we’re sticking with separate files.

The HTML for the search box is simple:

<section id="search-box">
        <label for="searchbox">Search:</label>
        <input name="searchbox" id="searchbox" type="text">
    <ul id="results-container"></ul>

Is it redundant to use both name and id attributes? Maybe. I tried removing the name attribute and again it broke. No search results show up, and no error messages in the console to debug. 🤷

This search uses the same json list of posts that I used for the random post list. All there is to go on in this list is post title and any tags, and most posts are untagged. As a result the search behaviour is pretty crude, the quality of results varies a lot. It works best for quickly getting to a post where you already know the title.


I added a new webring, using this plugin, inspired by Drew Devault’s openring. And I messed a bit with the styling. Let me know if you would like to be part of my webring!

The webring now makes the blogroll redundant, although I would still like to keep a full feedlist somewhere to publicise the sites I personally subscribe to.

I’m a bit concerned that the webring refreshes the RSS feed every time I build the site. I changed the build script to take into account build failures by putting the build command into a loop until it succeeds.1 This gears the site build process a lot more like something I can just ‘fire and forget’. Thankfully the picture tag plugin (which causes build failure) runs before the webring plugin, is this behaviour by design? If so, how can I tweak it? Changing the order of the plugins listed in the main config file doesn’t help.

The main scenario on my mind is when I’m actively working on the site, rebuilding manually a lot, which means it’s hitting every site in the webring every time I rebuild? That seems like spambot behaviour, not good internet etiquette.

Also the location of the webring folder changes based on which folder you run the build command in. It’s not supposed to do that! It took me by surprise and I had another look at the config file but didn’t find a fix. This plugin is weird.

Overall style

The index has no pictures, no external webfonts, no blocks with different-coloured backgrounds. It’s all text laid out with nothing but white space separating different sections.

Looking at the style of individual posts, the downside of starting off with a classless CSS framework is that these web pages end up looking a lot like… structured documents.
That’s by design, HTML is fundamentally a document markup language. The blog index has a collapsing multi-column grid layout, but even then it’s all just lists within columns of text. I like producing good semantic HTML, it just needs something else to look less brutalist.

dark mode

I made a green glowing-neon dark mode, and I much prefer that aesthetically.

Subresource Integrity Everywhere

All scripts and styles are loaded in their own files separate from the HTML. Hashes for the main files are generated as part of the build script.2 For snippets of specific javascript (such as used in this post), I generate a one-off hash with the expectation that the file won’t change. All that is paired with a simple CSP which forbids inline javascript.

If you’ve visited the site anytime in the last month and seen an unstyled page, that’s probably because the SRI hash didn’t match the cached stylesheet, and the browser refused to apply the styling. This is the expected behaviour, although probably not a good user experience.

Subresource integrity is supposed to protect you from whatever CDN is delivering the script files. If the hashes match then you can be sure the file I upload to AWS is the same one you get in your browser. Nothing has been messed with in transit, everything secure.

But wait, here is another threat model to consider!
In my case everything comes from the same CDN service - Cloudfront. Since AWS can see both the HTML and script files from the same origin, it could insert malicious code into the script, generate a new hash, and replace the hash in the HTML file.

Given the above problem, I’m in two minds as to whether this is a useful security feature. I see it as a way of ensuring good working practices, reduce the mixing of styles and scripts and content, but it causes a lot of hassle and feels superfluous.


The index now has two columns to take up more space on a horizontal monitor, while maintaining a good vertical layout on mobile.

Here’s what it looks like when you expand and contract the viewport width.

I already added a grid layout to the old post list, but it wasn’t used to its full potential. With this new layout the grid behaviour changes a lot more with different media queries.


I added contain: content to some lower-level elements which don’t rely on anything else in the page. The purpose of this property is to isolate elements from the document tree, giving an indication to the browser which helps optimise rendering performance.

Containing the layout blocks margins from collapsing. I built the layout taking into account margin behaviour and now I’m reluctant to mess around with spacing again in order to resolve it. So my approach has been to identify and contain elements which are to the greatest extent already self-contained.3

Is CSS rendering performance an issue? I’m not sure. The expected use case for CSS containment is a large document tree full of elements all dynamically changing layout; that would be an issue on low-spec devices. On this site the main performance target is largest contentful paint, and once everything is on the screen the page doesn’t change much. Following that, if only an inconsequential fraction of page load time is dedicated to layout calculation, then a speedup in layout performance won’t have a meaningful effect.

On the other hand, there’s no noticeable downside to containing CSS like this.


  1. The build fails if libvips runs out of memory while it’s compressing images, and this happens regularly with image-heavy posts. My clever solution to this memory leak is to just keep repeatedly rebuilding the site until it succeeds. 

  2. I’m sure I have alluded to this before on this blog, but I’ll go through it again. 

  3. If you go out of your way to avoid collapsing margins, some good news, the contain property un-collapses all margins around it.