Jekyll responsive images with srcset

First things first, let me define the term “responsive image”

Now what I am talking about in terms of a responsive image is serving different images in HTML for different situations depending on device breakpoints. (is there a different term for this?!)

So, what’s the big deal you may ask? Well, optimisations. Have you not been in the situation where you’ve completed a simple (or not) website and wanted to benchmark your outstanding coding abilities against Page Insights? You’ve got great HTML structure, perfectly optimised and minimised CSS and JS, enabled browser caching and… then, the thing spits out 63/100 with “Optimise your images” as the first optimisation suggestion?

“That’s it, I’m out, won’t ever write a single line of code again!!1!” (Oh, perhaps that’s just me…)

Anyway, this can be changed and responsive images is one (of several) image optimisation techniques for this purpose.

Also, we’re not using a CDN

This is not to say CDNs shouldn’t be used, but let’s not over-engineer small projects.

TL;DR We’ll use the srcset attribute of <img> to optimise image delivery. Not using a CDN.

By the end of the article:

  • your site will automatically generate responsive images based on a source image
  • Jekyll will scan your markdown for images and generate the <img> HTML tag so it uses the srcset attribute with the responsive images (this means you only set this up once and not need to worry about it later — yay!)

Jekyll responsive images plugin

Adding the plugin to your site

gem “jekyll-responsive-image”

Then add another entry to your plugins array in _config.yml:

- jekyll-responsive-image

Customising the plugin configs

responsive_image:
# [Required]
# Path to the image template.
template: _includes/responsive-image.html #THIS ONE
# [Optional, Default: 85]
# Quality to use when resizing images.
default_quality: 90
# [Optional, Default: []]
# An array of resize configuration objects. Each object must contain at least
# a `width` value.
sizes:
- width: 480 # [Required] How wide the resized image will be.
quality: 80 # [Optional] Overrides default_quality for this size.
- width: 800
- width: 1400
quality: 90
# [Optional, Default: false]
# Rotate resized images depending on their EXIF rotation attribute. Useful for
# working with JPGs directly from digital cameras and smartphones
auto_rotate: false
# [Optional, Default: false]
# Strip EXIF and other JPEG profiles. Helps to minimize JPEG size and win friends
# at Google PageSpeed.
strip: true
# [Optional, Default: assets]
# The base directory where assets are stored. This is used to determine the
# `dirname` value in `output_path_format` below.
base_path: uploads
# [Optional, Default: assets/resized/%{filename}-%{width}x%{height}.%{extension}]
# The template used when generating filenames for resized images. Must be a
# relative path.
#
# Parameters available are:
# %{dirname} Directory of the file relative to `base_path` (assets/sub/dir/some-file.jpg => sub/dir)
# %{basename} Basename of the file (assets/some-file.jpg => some-file.jpg)
# %{filename} Basename without the extension (assets/some-file.jpg => some-file)
# %{extension} Extension of the file (assets/some-file.jpg => jpg)
# %{width} Width of the resized image
# %{height} Height of the resized image
#
output_path_format: assets/resized/%{width}/%{basename}
# [Optional, Default: true]
# Whether or not to save the generated assets into the source folder.
save_to_source: false
# [Optional, Default: false]
# Cache the result of {% responsive_image %} and {% responsive_image_block %}
# tags. See the "Caching" section of the README for more information.
cache: false
# [Optional, Default: []]
# By default, only images referenced by the responsive_image and responsive_image_block
# tags are resized. Here you can set a list of paths or path globs to resize other
# images. This is useful for resizing images which will be referenced from stylesheets.
extra_images:
- uploads/*/*/*/*.{jpeg,jpg}

Adding the responsive image template

{% capture srcset %}
{% for i in resized %}
/{{ i.path }} {{ i.width }}w,
{% endfor %}
{% endcapture %}
<img src="/{{ path }}" alt="{{ alt }}" srcset="{{ srcset | strip_newlines }}">

By now you the plugin is fully set up and usable with the responsive_image tag as provided in its documentation. However, having to use the tag every time for every single image is quite annoying and requires you to write code. More importantly, this will not really work with markdown images.

Suppose you are using a frontend-friendly CMS to generate your content, having to manually change the HTML output is simply not feasible and impossible if you want to let content writers do their job. This is why we are…

Automating responsive images in markdown too

If you don’t already have one, create a _plugins folder at the root level of your site. Inside, create a img-tag-transform.rb file and copy and paste the following:

Jekyll::Hooks.register :posts, :pre_render do |post, payload|
docExt = post.extname.tr('.', '')
post.content.gsub!(/!\[(.*)\]\(([^\)]+)\)(?:{:([^}]+)})*/, '{% responsive_image path: \2 \3 %}')
post.content.gsub! 'path: /', 'path: ' #you can probably optimise this a bit
end

This bit of code basically replaces markdown images in your posts with the responsive image tag, which then triggers the plugin we set up earlier.

We’re done!

By the way, you can check these and my other articles on my website blog here as well as subscribe to the RSS feed.

Till next time. 😉

--

--

product owner @TwoKings web design agency | https://www.linkedin.com/in/valchevivo/

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store