A different GIF will displayed below depending on your browser’s prefers-reduced-motion and prefers-color-scheme settings. There’s four different possibilities:

A white cat

I hadn’t used prefers-reduced-motion before but I saw a chost from Kore linking to a blog post about accessibility and GIFs and decided I wanted to follow it but I also didn’t want to have to manually write the HTML code for it each time. Thankfully programming is the art of being tactically lazy and I can put some effort in up front and solve an interesting problem once and then let my site generator handle it automatically from then on.

Also thankfully I had done something like this before after taking inspiration how Luna’s blog handles images. I don’t have high D.P.I. images but I do have different dark and light mode versions of images for the The “the Ring” Podcast series tracker chart and the Dracula International diagram I made.

The way I had initially done that was, characteristically, a mess. I wrote a custom custom Liquid tag to handle it which meant that instead of actually using the existing, basic Markdown syntax I had to put images into my posts with something like this:

{% image /images/easóg.gif %}

So revisiting this to include prefers-reduced-motion options I decided to do it differently this time. A way that would allow me to just type the normal Markdown syntax and let my code handle everything else.

![A white cat](/images/easóg.gif "Easóg")

The next step was to look into how to extend and customise Jekyll’s Markdown parsing and output but that sounds hard and I didn’t want to do that so I just used a regular expression1:

/((!!?)\[([^\[\]]*)\]\((.*?) *("([^"]*)")?\))/

This runs against the raw Markdown before it’s parsed into HTML and pulls out the link, alt text and title. That last part is also a big improvement over the custom tag I previously made as that didn’t support alt text or titles at all.

The code then takes the link and checks if there are any alternative versions listed in the site’s static file list like easóg.dark.gif, easóg.static.gif or easóg.dark.static.gif. when writing a new post now I don’t have to do anything extra other than have those other versions with the right naming scheme in the same folder as the original image.

From there it it compiles it into HTML and replaces the original Markdown in the document:

<picture>
  <source srcset="/images/easóg.dark.gif" media="(prefers-color-scheme: dark) and (prefers-reduced-motion: no-preference)" />
  <source srcset="/images/easóg.gif" media="(prefers-reduced-motion: no-preference)" />
  <source srcset="/images/easóg.dark.static.gif" media="(prefers-color-scheme: dark)" />
  <img src="/images/easóg.static.gif" alt="A white cat" title="Easóg" />
</picture>

Well, actually it does something else too. You might have noticed in the regular expression up above I am actually checking for an optional, second exclamation mark at the start of the image tag. That’s my own extension of the syntax. If I’m doing my own parsing I might as well go wild with it. If there are two exclamation marks at the start of the tag it also wraps the image in a link to itself and adds an extra class:

<a href="/images/easóg.static.gif" class="dynamic-image-link">
  <picture>
    <source srcset="/images/easóg.dark.gif" media="(prefers-color-scheme: dark) and (prefers-reduced-motion: no-preference)" />
    <source srcset="/images/easóg.gif" media="(prefers-reduced-motion: no-preference)" />
    <source srcset="/images/easóg.dark.static.gif" media="(prefers-color-scheme: dark)" />
    <img src="/images/easóg.static.gif" alt="A white cat" title="Easóg" />
  </picture>
</a>

The classes are to enable a little bit of Javascript2 to swap out the destinations of the links on the fly when swapping if the user’s media preferences change. Whichever one you currently see in the browser is the one you’ll go to if you click on it.

I might review the double bang syntax if I can figure out something that could be added to the tag that would get stripped out and ignored by a normal Markdown parser for better compatibility. If only Markdown had comments.

Is this a robust solution? Absolutely not! Will I eventually run into annoying weird cases that make me bang my head against the wall as a result of this? I already have! While writing this very bog post! Because the regular expression cannot tell that the markdown code example I have above is not meant to be parsed and turned it into HTML, making it impossible to show the before part of the before and after. Did this make me go back and implement this in a better way? No!

I added some metadata to this post telling it do disable my custom image parsing, made the parser skip doing anything if it finds that metadata on a page and then hardcoded the example at the top of this page. That’s right: This post isn’t actually using the one thing it’s meant to be demonstrating!

  1. I could have also tried parsing the resulting HTML instead of the Markdown like Luna did but that also seemed like it would take slightly more effort. 

  2. One of only three things Javascript is used for on the site.