This summer, months after my previous post, I decided to give this site a complete overhaul. I started from scratch in a brand new codebase. This new site has an entirely new, bold look. I've switched static site generators, too—I'm using Eleventy instead of GatsbyJS.

I had been discontent with my old site for a while. The design, which was a modified version of one of Gatsby's templates, didn't feel like it expressed me. I found the tooling confusing and frustrating, and every time I added new functionality to the blog, I felt like I was fighting with my own site. The site, even after it was built and optimized, felt too applike and bloated for the kind of blog site I'd like to have.

I could have addressed some of those concerns in the previous site, but to address all of them, I felt I needed a blank slate, a fresh start.

That's when Andy Bell published his phenomenal Learn Eleventy From Scratch course. I really, really enjoyed the course, and it was exactly the catalyst I needed to get started.

In this post, I'd like to document the factors that led me to the site I have now, both in design and stack. I'm doing this both in the hopes that it can help someone else who might be going through a crisis of design or tooling, and to create an archive of my own motivations to look back on.

Out With The Old...

I'll start with an admission: grass-is-greener syndrome is absolutely real, and it impacted this overhaul. I don't believe this coat of paint will last forever, and I think it's totally reasonable that I will migrate away from Eleventy someday.

That said, I'm a staunch believer in writing the code you wish to see in the world, and in the year since I first launched the blog, it had become very clear to me that my old site was not that.

The Inexpressive Design

The appearance of my site was the first signal to me that I wanted a change. When I launched the blog a year ago, I used the gatsby-blog-starter template, and I modified the layout and CSS from there.

Screenshot of the old site. The layout is a single column down the middle, and there's very little color. Each post snippet has a different emoji next to it.
The old site

The template is perfectly serviceable, and I think the end result looked fine. No matter how hard I tried, though, I couldn't shake the feeling that it looked very templatey. I wanted something that stood out and which felt like I had designed it.

Fighting With Tooling

Frameworks have opinions, and static site generators are no exceptions. I initially picked Gatsby because it leverages React, which I already had a lot of experience with. Writing a site in React and having it built into static sites seemed convenient, so I went with it.

In time, I came to realize that Gatsby has several strong opinions... and that I disagreed with most of them. Some of those opinions include:

These opinions will make sense for some users and some applications. They just didn't fit my needs.

Take the GraphQL opinion. It's a perfectly fine opinion if your site needs to scale a lot. However, it felt overengineered for my use case. I found some aspects, like the lack of a straightforward way to provide default values in GraphQL queries, genuinely frustrating.

I found myself trying to align better to Gatsby's way of doing things. I felt like I was writing code to appease the tooling, rather than the code I would have wanted to write. I was fighting with my own site.

So far, I've been talking about the technical opinions that shape GatsbyJS as a framework. This is largely because, when I was in the process of migrating away, these were the main opinions I had to go on. Since migrating, I've learned of how Gatsby, Inc. has treated their employees and contractors—treatment I find unconscionable. This sours my opinion of Gatsby, and it would feel wrong not to mention it.

This Blog Is Not An App

In hindsight, the choice to make this blog as a React app—even using a static site generator—wasn't a great fit for several reasons.

For one thing, Gatsby apps leverage server-side rendering and hydration. A static HTML version of your site, generated during build time, is sent to your user initially. Then, more JavaScript is sent that converts the page into a single-page React application behind the scenes. This can give you a fast initial page load combined with the functionality of single-page applications. However, your users still have to pay the cost of your JavaScript. That might be fine for some apps! But most blogs, including mine, are largely static, so hydration is generally added bloat.

That single-page application functionality poses accessibility concerns, too. For instance, single-page applications override the browser's default navigation behavior, and replace it with client-side routing. This means it's up to the application to handle routing in an accessible manner, including focus management and ensuring screenreader feedback. While the Gatsby team has invested heavily in providing an out-of-the-box solution for these things, when it comes to sites like mine that are so thoroughly not applications, nothing beats a real page load.

I had one last concern with having my blog be a React app: it was tightly coupling me to React. That tight coupling introduces inertia—the longer I waited to migrate away from the React stack, the harder it would be to migrate.

...In With The New!

The discontent I felt with the previous version lingered for a while, and by the time I took Andy's Eleventy course, I was ready for a change. I wanted a site that could be expressive without sacrificing accessibility or performance, and I wanted tooling whose tide I could swim with, rather than against.

Let's talk about how I got there.

The New Look

Even though the design was the first domino of discontent to fall, it took a long time and a lot of experimentation for me to figure out what the new site should look like. At first, I was using such descriptive adjectives as expressive and not-a-template.

At first, I copied over an HTML page for one of my early articles and opened up a brand new CSS file. From there, I just kind of tried things, and I ended up with...

Browser screenshot of a textbooky blog design. The blog title is displayed along the top in a big, blue cover bar, and the rest of the site has coral and light green accents.

It was fine, I think, but not particularly expressive. When I asked my friends for feedback, I heard the word textbooky multiple times, and they were absolutely right. I went back to the drawing board. From there, I kind of floundered for a bit.

Then, one night, I had some inspiration—not for the site design, but for a logo. I opened up my vector-editing software of choice, Inkscape, and threw this together:

A logo consisting of two blocky shapes. The first is red, and vaguely resembles a capital B without its vertical line. The second is the same as the first, only yellow and rotated to resemble an M.

It was a stylized take on my initials, inspired by the 90's geometric aesthetic. It needed some workshopping—huge thanks to my friend Morgan for his insight there—but the seed was sown.

The current logo. The same two blocky shapes, but better aligned and rotated to highlight symmetry. A drop shadow has been applied to add to the 90's geometric aesthetic.

This new logo set the tone for the rest of the new design: bold, colorful, and playful. It also solved the problem of which color scheme to go with—from here on, my palette would be filled with purples, reds, and yellows.

Color schemes, I learned, are difficult to use with intentionality. Since purple was quickly assigned the role of primary, background color, that left me figuring out how to use red and yellow as accent colors. One decision that felt important to me was choosing to use yellow for hyperlinks. Since most web users are accustomed to seeing blue links, I decided to reserve yellow for links and buttons alone, hammering home that on this site, yellow means clickable. Design affordances are fun.

My choice of typefaces also had to meet this tone of bold and playful, without sacrificing accessibility. I decided to limit myself to three typefaces: a "brand" typeface for headings, a typeface for body text, and a monospace typeface for code snippets.

  • Nexa is my brand typeface, which I use in headings and page titles. Because headings are large, I could go for a bolder, more playful typeface without sacrificing too much legibility.
  • Inter is the typeface for my body text. Here, I tried to optimize for readability. I like Inter because it's no-frills.
  • Fira Mono is my monospace typeface. As far as monospace typefaces go, I think it's sleek and, unlike its ligature-equipped variation, no-frills. Plus, I think it pairs well with my other two typefaces.

The New Stack

Working through Andy's Eleventy course, I was introduced to a static site generator whose opinions felt very different from Gatsby's. Namely, one key opinion seemed to be that in static sites, dynamic content and reusable layouts are best powered by templates, rather than components.

At first, I wasn't sold. The templating felt kind of clunky, and I initially found the dynamic content injection to be a little unintuitive, with all sorts of ways in which any piece of data could be locally overridden.

However, I soon came to appreciate what feels to me like Eleventy's biggest opinion: that its own job was to get out of your way as much as possible. You can pick your own preferred template language (or switch between multiple templating languages) and you could exploit as much or as little of the data cascade as you like. Really and truly, in Eleventy, it's your content, and you get to set it and inject it however you like.

Under the hood, Eleventy uses markdown-it to parse your Markdown files. While I wish markdown-it had more complete documentation, I have been able to leverage and create a few plugins to extend my Markdown documents. Some of those extensions have been:

  • Fencing blocks of text with ::: to make sure they're rendered in an <aside />
  • Using asterisks and underscore to distinguish whether to use <em> and <strong> or <b> and <i>
  • Enabling tabpanel experiences
  • Ensuring all images in my posts load lazily by default

What strikes me about all of this is just how easy this could be to migrate away from should the time arise. With the old site, if I wanted to migrate my React components to a different static site generator, my only other option is pretty much Next.js. With this new site, however, I won't need to port over complicated, potentially logic-heavy components. I won't need to stress over finding a platform that supports MDX. Templates strike me as more flexible in that regard, more copy-paste friendly. Plus, I'll likely be able to bring markdown-it and my plugins with me.

The Lightweight Experience

One last key opinion that Eleventy holds: static sites should be, well, static. The markup generated from your templates is what gets sent over the wire to your users. There's no undercover hydration. The only JavaScript that gets sent is what you choose to send. Thus far, the only JavaScript I'm sending is the necessary scripts for the demos in some of my articles, as well as a miniscule amount to make some tab panel functionality happen.

Without component logic at my disposal, I've needed to become so much better at progressive enhancement, and I've been even more careful with my semantic markup. This has had the side effect of cutting down bloat even further, by striving for even less markup. I've tried to get away with using as little markup as possible. I'd be genuinely proud to have someone View Source.

The minimal markup affected my approach to styling the new site. In the old site, certain styles necessitated certain markup, like wrapper elements. The new site, inspired by CSS Zen Garden and its spiritual successor Style Stage, is designed for totally replaceable styles should the need arise. Styles are written for the markup as they should be, and not the other way around. If I ever decide to go for a fresh coat of paint, I'm in a much better place to delete my styles and start anew than I was on the old site.


I'm genuinely psyched about this new site. Much of that excitement comes from having a blank slate where I can put what I've learned over the past year about performance and progressive enhancement to good use, free from the clutches of technical debt. It also stems from having a tool in Eleventy that I feel like I can work with, rather than against.

If the grass is greener for you, maybe it's time for a greenfield.