Website Updates (2024)

I did a bunch of more updates to this website, including adding a dark mode. Most of the other changes are either invisible or barely noticeable. That's OK. My several visitors will appreciate them. Or at least I'll appreciate them.

Dark mode and syntax highlighting

I added a dark mode using CSS, with prefers-color-scheme (widely availabe as of 2020). I switched syntax highlighting (using Pygments) from inline styles to CSS classes, which use different theme colors for light and dark modes. This change will cause the RSS feed to not have syntax highlighting (since RSS readers shouldn't interpret CSS classes), whereas before some RSS readers may have allowed the style elements. I think RSS feeds aren't supposed to be styled, so that's probably OK.

RSS feed

I reduced the size of the RSS feed by only including summaries for old posts, rather than the full content. Also, if I write too many more posts, the RSS feed will stop including the oldest posts. I really prefer when RSS feeds include the full content with each post, but I think that's less useful for very old posts.

Markdown renderer

Many of these pages are generated from Markdown. I added support for it in 2014 using Python-Markdown, which was probably the obvious choice. Since then, some folks standardized Markdown as CommonMark, which is used widely in VS Code and GitHub (GitHub Flavored Markdown extends CommonMark), among others. The differences between Python-Markdown and CommonMark are small but annoying, so I've switched to markdown-it-py. Since this website is generated as static pages, it was relatively easy to diff the HTML and RSS across this change for manual review.

Mako parsing conflicts

This website contains both HTML and Markdown pages and templates. The Markdown pages are processed through the Mako templating engine and then the Markdown renderer. The HTML pages are just processed through Mako. Most of what I use Mako for is basic variable substitution, loops, and if statements. It also allows running full Python code inside templates, which I like. (I write the templates, so I can live with myself abusing them. I wouldn't want this in a larger team project.)

Mako's syntax is usually not in conflict with Markdown or HTML, but I've found three exceptions where there are ambiguities:

${variable}

Mako interprets the occasional ${variable} in a shell script (or this paragraph) as a Mako variable substitution. Sometimes I want one behavior (Mako) and sometimes I want the other (literal). Fortunately, when this happens, it's unlikely that the variable exists in Mako's scope, so it usually causes a build error.

I haven't found an easy way to escape ${variable} locally. The best approach is to use <%text> to opt out of Mako for an entire section. Otherwise, using &dollar; is an option in HTML, but not within a `code block` in Markdown (see CommonMark example). Another approach is to define a Mako variable called dollar with a value of $, then write ${dollar}{variable}.

Trailing backslash

Mako consumes a trailing backslash at the end of a line and merges the line below it. Many programming languages use this syntax too. It's easy to forget about this and get poor rendering of code blocks. Similar to the dollar issue, <%text> is a good way to disable it, or you can use &#92; in HTML but not Markdown, or you can define a backslash variable.

I found that I was only using the trailing backslash feature of Mako in one place, so I wanted to turn it off and have a default that won't keep biting me. Unfortunately, substituting \\ for \ at the end of the line doesn't help, as consuming the second backslash is baked into Mako's lexer. Instead, I added a workaround that replaces a trailing \ with a unique string before Mako runs and then replaces that string back to a \ after Mako runs. I think that should in most contexts, including code and non-code and Mako-enabled and Mako-disabled regions. This does completely prevent using a trailing backslash in Mako and Mako Python blocks (<% ... %>), but those are usually unnecessary. If I forget and try to use a trailing backslash in Mako, it's likely to cause a build error, which is the behavior I want.

Leading hashes

Mako interprets ## at the start of a line as a comment, which Markdown uses for <h2>. I found out about this one almost immediately after starting to use Markdown on this site. I don't need that style of Mako comments, so I wanted to disable them.

I've had a workaround in place for a while that pre-processed the input and injected <h2> tags before Mako ran. That worked well for me, but in theory it would break ## if used in code blocks or in Mako Python blocks (<% ... %>).

I've updated my workaround to replace a leading ## with # followed by a unique string before Mako runs, and then replace it back after Mako runs. I think that'll work in all contexts.

Social sharing metadata

I added some meta tags for social media. The Open Graph Protocol metadata is used by Meta, LinkedIn, and others, but that site is archived on GitHub. Facebook's page is another resource. Twitter has its own metadata but will largely use Open Graph metadata if available. fediverse:creator is used on Mastodon.

Note: there's a technical distinction between:

<meta name="..." content="...">

and

<meta property="..." content="...">

where some fields want one or the other.

This metadata required some code generator changes. Similar to the page title, the metadata is set above where the main page content is rendered. That information has to be "pushed up" to be available outside the main content. Also, the pages had to be made aware of their URLs for og:url.

The OpenGraph Protocol requires og:image to be set, yet most of my pages don't have an image. I created a larger version of the favicon as a default.

Here's an example of a link to this blog post on Mastodon:

Mastodon share example

Favicon

Since I redrew the favicon as an SVG for the social sharing image, I also added the SVG for browsers that support it. I created a dark mode variant, but I don't think mainstream browsers support that yet (see the links from this issue). Firefox seems to ignore the prefers-color-scheme and take the last SVG. Other browsers may default to the first SVG, so I have sandwiched the dark favicon declaration in between two light ones:

<link rel="icon" type="image/svg+xml" sizes="any"
    media="(prefers-color-scheme: light)" href="favicon-light.svg" />
<link rel="icon" type="image/svg+xml" sizes="any"
    media="(prefers-color-scheme: dark)" href="favicon-dark.svg" />
<link rel="icon" type="image/svg+xml" sizes="any"
    media="(prefers-color-scheme: light)" href="favicon-light.svg" />
<link rel="icon" type="image/png" sizes="16x16"
    href="favicon.png" />

Hopefully dark mode favicons will start working in more browsers over the next few years.

HTML and CSS updates

I updated and modernized some HTML and CSS, including use of these newer features:

  • var() and custom properties (2017) are useful for defining theme colors for light/dark modes.
  • :has() (2023) was useful in styling just the <pre> elements that contain <code>.
  • :is() (2021) helped save some duplication for styles related to h1-h6.
  • :not() (2021) helped keep some styles self-contained.
  • box-sizing: border-box (2015) is old news but I started this website in 2007.

For testing dark mode and the styling updates, it was convenient to have the blog index page render the entire contents of the blog on one page that I could scroll through quickly.

I tried to keep the website usable with older phones. For example, I assume iOS users have Safari 15 but not necessarily Safari 16 or newer yet. These are some CSS features that look nice but that I've avoided for now until they're more widely available: