Daniel Pietzsch

Responsive images

I have now added the ability to display responsive images on this site.

And just as with my photo journal, I’m using the fantastic jekyll-responsive-image plugin1 to do so.

What I did differently this time, though, is that I can use the standard markdown syntax for images, instead of using the custom liquid tag. There are a few reasons for why I wanted it this way:

  • Markdown syntax is nicer and more convenient to write,
  • I will have less Markdown source files be “littered” with liquid syntax,
  • it hides the complexity that comes with responsive images, and
  • it will enable me to use more standard tooling that only works with the Markdown syntax, while still enabling me to create posts with responsive images.

Replacing Liquid syntax with Markdown

In order for this to work, I can run some code in a pre-render hook that replaces the standard markdown syntax with said custom liquid tag before Jekyll actually converts the file to HTML.

This pre-render hook needs to basically translate the Markdown image syntax to the liquid tag that the jekyll-responsive-image plugin expects. E.g., I want to replace syntax like this (in standard markdown notation):

![alt text](image.jpeg "The title for this image")

…with something like this (which will be the source Jekyll uses to convert to HTML):

{% responsive_image path: image.jpeg alt: "alt text" title: "The title for this image" %}

The Regular Expression

And in order to do so, I need to parse all those different parts of the markdown syntax – image path, alt text, and title text – so I can reuse them when it comes to constructing the liquid syntax. Here’s the regular expression I found to be working – with alt- and title-attributes both being optional:

^\!\[(?<alt>.+)?\]\((?<path>\S+) ?"?(?<title>.*?)"?\)

The Prerender Hook

Here’s the complete code from the pre-render hook2, that does its thing each time right before a markdown file is converted to HTML3:

Jekyll::Hooks.register [:pages, :posts], :pre_render do |post, payload|
  document_extension = post.extname.tr('.', '')
  # Only process if we deal with a markdown file
  if payload['site']['markdown_ext'].include? document_extension
    new_content = post.content.gsub(/^\!\[(?<alt>.+)?\]\((?<path>\S+) ?"?(?<title>.*?)"?\)/, '{% responsive_image path: \k<path> alt: "\k<alt>" title: "\k<title>" %}')
    post.content = new_content
  end
end

An example

In addition to serving the original file, I decided to generate five smaller versions: 320, 640, 960, 1280, and 1920 pixels wide respectively.

And here’s the first responsive image in a blog post:

Zoe and some rubble
  1. My own fork, though, to be precise. 

  2. Thanks to David Jacquel for the original version

  3. And of course, I ran into problems while writing this very article: Since the hook simply processes the whole document – without paying any attention to markdown-specifics, it would have also replaced the standard-markdown-image-syntax code example above. To circumvent the problem, I added the ^ to the regular expression, so that the hook only replaces those occurrences that start at the beginning of a new line. Because then I could use Markdown’s indent-four-spaces-for-code-markup syntax (i.e. not at the start of a new line), which was not replaced – and instead renders the example above, as intended .