Jekyll responsive images with srcset

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

“Responsive image” can be quite easily confused within the context of responsive design, not least because Google’s first search result points out to a w3schools tutorial on, well, responsive images that scale up and down on different screen sizes.

Also, we’re not using a CDN

A CDN solution like Cloudinary can do all of today’s work for us. But assuming all you are using Jekyll for is your blog, portfolio or tool documentation, it just feels a bit excessive to deploy a CDN service for such a limited purpose. Plus, for me a lot of the beauty that comes with using static site generators for small projects is, quite literally, your repository being the world to you — it’s just all in there, nice and neat!

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

First of all, lets install the jekyll-responsive-images plugin. All it does is generate a set of different-sized images from a source image, which we will then use in the srcset attribute.

Adding the plugin to your site

Locate your Gemfile and insert the following line (next to your other plugins):

gem “jekyll-responsive-image”
- jekyll-responsive-image

Customising the plugin configs

Now we need to customise the plugin’s configuration. A sample configuration is available below, which you can copy and paste inside _config.yml. Twist the configs as you like (here is a useful article for src sizes in particular), just make sure you’re using the responsive-image.html template, which we will create next.

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

So we now have the plugin fully configured! But we are not quite done yet. To actually use it to generate our HTML, we need to create the responsive-image.html template we specified earlier. Create the file inside your project’s _includes folder and add the following content:

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

Automating responsive images in markdown too

To do this, we’ll use Jekyll hooks. Basically they allow you to intervene in the site generation process to tweak it here and there so it lets you achieve a specific purpose.

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

We’re done!

If you made it all the way to here, well done! And thank you. Hopefully this has been helpful to you and please let me know if you have any questions or suggestions for improvements (I’m a learner still, and will probably be for the rest of my life)!

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