Shuhei Kagawa

New look

Feb 23, 2021 - Blog

I updated this website’s design and replaced its static site generator with Eleventy. Here are some notes about the new look and implementation details.


I had used only sans-serif fonts on this website. Serif fonts felt too fancy. But I like serif fonts on paper books. Many of them use serif fonts regardless of the fanciness of their contents. I wanted to do so for my website as well. But I didn’t know which font to use. There are so many fonts in this world, and Google Fonts has tons of serif fonts. So, I used a type pairing from Typewolf—Libre Franklin for headings and Libre Baskerville for body text.

For code blocks, I chose DM Mono. DM Mono is a monospace font commissioned by Deep Mind—yes, they have their own fonts. Its “f” has a fancy touch. I use it for coding these days after years with Fira Code.

function greet(name) {
  return `Hello, ${name}!`;

This website has mostly text and a few images. Web fonts are the only luxury that I put.


I replaced my home-grown static site generator using gulp with Eleventy. I liked gulp—it was a good use case of Node.js streams. But I wanted to try something new. I picked Eleventy simply because I heard its name many times and it runs on Node.js, which has a large ecosystem of web tooling.

Also, I removed Disqus and Google Analytics. This website is almost free of cookies now. The last one standing is Cloudflare’s bot detection cookie, which will be removed in May 2021.

Implementation details

I took image optimization techniques from google/elventy-high-performance-blog—next-gen image formats (AVIF and WebP), multiple image sizes (srcset), blurred placeholders with SVG, immutable image URLs, aspect ratio by setting width and height, lazy loading and async decoding. The implementation is rather wild. It parses each full HTML with jsdom, finds <img> tags, read and optimize linked image files, and replaces the <img> tags with optimized <picture> elements.

I implemented a funny feature that inserts <wbr> into longCamelCase words—like long<wbr>Camel<wbr>Case—to break them on small screens. Some posts on this website have long titles such as “Check your server.keepAliveTimeout.” Those titles overflow on small screens. I could use a smaller font size for the titles, but I wanted to use a big font. <wbr> HTML tag tells browsers that they can break lines there if necessary. I created a template filter to insert it.

Heading with  on the left and heading without it on the right

This website has a feature to generate Open Graph images—or Twitter Card images—using node-canvas for blog posts without any images. I used Eleventy’s pagination with size: 1 to implement it. It’s a cool way to generate another file for each post in a collection.

Another trick worth mentioning is generating CSS as Eleventy’s global data. Based on a regular CSS file, I wanted to inline Google Fonts CSS at build time (and preload woff2 files in it), apply postcss to it for transformation and optimization, and embed it into each HTML file. The quick tip to inline minified CSS on Eleventy documentation was not ideal for my use case. It didn’t feel like a valid use case of a filter to asynchronously fetch remote data, and it took a few extract seconds to run the same CSS optimization for every HTML file. Global data with JavaScript runs only once regardless of the number of templates that use it, and we can do almost anything.

Thoughts on Eleventy

I had a good experience with Eleventy. It was easy to start with, and its hot reload worked out of the box. Its data cascade is powerful. But it took some time for me to understand the powerful data (and content) cascade. To implement features inherited from the previous version, I had to read most of the documentation in the end.

It’s not the best tool for someone who just wants to write blog posts out of the box. You’ll need to write some JavaScript. But if you want to have fun writing JavaScript to implement whatever feature you like, it’s a great option.