Author’s Note: I’m currently in the process of migrating old blog posts to this new system. That may mean some links, syntax highlighting, and other details are broken or missing temporarily. Sorry for the inconvenience!

See this post in blue

Today’s post looks a far cry different from just two days ago, but last time we laid the groundwork for all sorts of customizations. Today, we’re going through a bunch of little optimizations, but you can hopefully already see the majority of them in action!

Adding lead images

Posts tend to perform better when they have an image associated with them. So it’s time for us to start adding some images. One great place to get do-whatever-you-want images is The images there are licensed under Creative Commons Zero, which means they don’t require attribution, you can use them for commercial works, creative derivative works, et cetera, et cetera. Here’s the one that I pulled for this post:

Since we already have a system for managing metadata, I’ve updated our front matter to include a lead image:

 title: The Post Title
 lead-image: sunlit-forest.jpg

But it’s not enough to just snag the image file. We also need to determine the overall color, so that we can set the background of the page to match. To do this, we’ll be a little tricky: we’re resize the image to a 1x1 square, and get the RGB color value of that pixel. Here’s the relevant part of our v0.3.0 template:

IMAGE=$(echo "$FRONT_MATTER" | grep lead-image: | sed 's/.*: //')
COLOR=$(convert lead-images/$IMAGE -scale 1x1\! -format '%[pixel:u]' info:- | sed 's/s//')
echo "
html {
  background: $COLOR;
#main-image {
  position: absolute;
  top: 0px;
  left: 0px;
  z-index: -2;
#main-image img { width: 100vw; }
<div id='main-image'><img src='$IMAGE'></div>

Now we have the image positioned full-width at the very top of the page, while ensuring that the background of the entire page matches the lovely dominant goldenrod color of the image. Lovely!

Adding gradients and noise

Adding an image isn’t quite enough, unless we want an uncomfortably disjointed backdrop:

What we really would like is for the image to fade out into the background. Can we do this? …not easily. What we can do is overlay a gradient that goes from transparent to opaque!

background: linear-gradient(to bottom, transparent, rgba(86, 68, 27, 0.9) 80%, rgba(86, 68, 27));

Stick that on top of the image, and get a near-seamless transition:

Unfortunately, depending on the image, the transition can still be a little rough. Gradients are tricky like that. So one way that we can blur the line between the image and the flat color is by muddying up the image a little bit with some “noise”.

One great place for noise is So off I went and built myself a noise texture:

By tiling the texture over the whole thing, we can make the gradient look even cleaner.

Voila! Now we have a way to spice up our posts with a lead image that seamlessly blends into a background color based on the image. For an even more drastic look, take a look at this very article, but with a different lead image.

The article card

Now that we have a lovely background, we can create a little card for our article content. Here’s the code:

<div id='main-card'>
  <article id='main-article'>
    <!-- Post Content -->

  #main-card {
    box-sizing: border-box;
    background: #fff;
    max-width: 768px;
    width: 95%;
    margin: 100px auto 20px;
    padding: 20px 0;
    box-shadow: 0 10px 20px rgba(0,0,0,0.19), 0 6px 6px rgba(0,0,0,0.23);
  #main-article {
    max-width: 640px;
    margin: 0 auto;
    overflow-x: hidden;
    width: 90%;
    font-size: 18px;
    color: #222;

This is actually split up into two components: one is the white “box” that you see on the screen, and the article is actually centered within there. This lets us have nice fat margins when there’s screen space, but lets the margins collapse as the browser shrinks.

I also stole the drop shadow from this article on Material Design. Material Design is a fascinating subject that we’re really not going to go into here. On to the next quick change!

Text styling

I don’t know much about typography. But there are a few small things that can really help things look better, and I’ve applied these rules to the entire page:

html {
  color: #222;
  line-height: 1.618;
  font-family: system-ui, -apple-system, BlinkMacSystemFont,
    'Segoe UI', 'Roboto', 'Oxygen', 'Ubuntu', 'Cantarell',
    'Fira Sans', 'Droid Sans', 'Helvetica Neue',

First, we change the default color from pure, plain black, to a very dark grey. There’s an argument to be made that you should never use pure black, because it’s not a natural color and will seem off-putting.

This can definitely go too far though, (see How the Web Became Unreadable), so we have to use some caution. Since the article card is pure white, bumping up the black just a little bit seems to make things look nice and pretty, and hey, it works for me.

Next, the line height. 1.618: The golden ratio. Really, anything beyond 1.6 isn’t going to matter much. But hey, the line spacing seems to work pretty well, and the number is magic. Moving on!

Lastly, we’re using a large set of fonts by default. The gist here is that different browsers on different operating systems will all end up picking up a font that happens to work really nicely in that environment. Running on Apple? You get the -apple-system font. Chrome? Roboto’s gonna do it for ya. Here’s a good article on applying this strategy. There’s also the benefit that your browser won’t need to download anything. These should all be fonts that exist on your machine.

Code highlighting

A lot of these posts have involved some code snippets, so it seemed to be an appropriate time to switch our Markdown processor to something that could support that for us. So now we’re changing that part of our template:

# Old style markdown processing
$(cat $FILENAME | sed '1,/---/d' | markdown)
# New style markdown processing
$(cat $FILENAME | sed '1,/---/d' | kramdown --syntax-highlighter rouge --no-hard-wrap -i GFM)

We’re using kramdown and rouge to do the heavy lifting here, and it’ll handle our Markdown, but also provide support for code blocks inside our posts like this:

 echo "Yo"


Rouge will wrap parts of the code in various <span> tags and then a small stylesheet makes them look all pretty. No more confusing code snippets, and it’s effectively a drop-in replacement for our old Markdown processor. Onward and upward!

Looking good!

So there we are. It’s been a fun week! We started off by setting up our build script to paste in some header and footer content, then moved on to integrating front matter and creating custom templates. Finally today, we’re able to take advantage of all that fanciness to create posts that are looking pretty darned swell.

All in all, none of these changes are really groundbreaking, but we’re a far cry from where we started a month ago: Let’s see what we can do over this next month!

←Previous Post | Next Post→