HTML5 picture element in Jekyll

What a nice view, eh?
This once was a 8.5Meg 4K image. Now how do you see it? If you click “view image” what do you read in the path? On my 1920x1080 desktop monitor I see assets/resized/images/1920/new-york-4k-view-at-sunset.jpg
. Cool! It’s a half an hour work, thanks to Jekyll and jekyll-responsive-image plugin by Wildlyinaccurate!
All you have to do is:
- add one line (and its comment) to the Gemfile
# Auto-resize and serve smaller images: https://github.com/wildlyinaccurate/jekyll-responsive-image gem "jekyll-responsive-image"
- run
bundle install
bundle install
- if something horrible goes wrong (like it happened to me1), install a couple more packets:
sudo apt install build-essential imagemagick libmagickcore-dev libmagickwand-dev bundle update && bundle install jekyll clean
-
add
jekyll-responsive-image
to the usedgems
into your_config.yml
gems: - jekyll-feed - jekyll-paginate - jekyll-responsive-image
- copy almost as-is the configuration found on jekyll-responsive-image plugin page and paste it inside
_config.yml
2responsive_image: # [Required] # Path to the image template. template: _includes/responsive-image.html # [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: 1920 quality: 90 - width: 1400 quality: 90 - width: 1200 quality: 90 - width: 1080 quality: 90 - width: 800 quality: 95 - width: 480 quality: 95 - width: 320 # [Required] How wide the resized image will be. quality: 95 # [Optional] Overrides default_quality for this size. # [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: false # [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: assets # [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/%{dirname}/%{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: true # [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: # - assets/foo/bar.png # - assets/bgs/*.png # - assets/avatars/*.{jpeg,jpg}
- add a HTML5 template file to be included and populated through Jekyll. In my case, I used the default name
_includes/responsive-image.html
.<picture> {% for i in resized %} <source media="(min-width: {{ i.width }}px)" srcset="{{ i.path }}"> {% endfor %} <img src="{{ path }}"> </picture>
- that’s it, restart
Jekyll
and try it out replacing your
with
{% responsive_image path: assets/images/my-huge-4k-image.jpg alt: "ALT-TEXT-My huge undownloadable image" title: "My huge undownloadable image" %}
Late evening UPDATE: after a whole day of fiddling with Liquid syntax, I realized that I don’t want, for almost any reason, a 320px image served on a Google Nexus 5 screen (1080x1920px). But this is exactly what was happening on my mobile! Also the Firefox Inspector (Ctrl-I) was totally sure that the right size for a Nexus 5 is 320x480px! Obviously this has something to do with screen size and pixel density, but the problem is that I don’t care. I want full HD pictures on my phone, exactly as on my desktop. This is the output of a whole day working on responsive images, maybe I should think a bit more about it and change my mind :)
And this is the final aspect of _includes/responsive-image.html
. It always serves 1920px images :)
<picture>
<!-- I still don't understand how this stuff works, the only thing I'm sure of is that I don't want to serve a 320px image on a Nexus 5, WTF! -->
{% assign sorted_sizes = resized | sort: 'width' | reverse %}
{% for i in resized %}
{% assign threexres = forloop.index | minus: 1 %}
{% assign two_x_res = forloop.index %}
{% assign onepointfive_x_res = forloop.index | plus: 1 %}
{% assign one_x_res = forloop.index | plus: 2 %}
{% assign size_minus_one = sorted_sizes.size | minus: 1 %}
<source media="(min-width: {{ i.width }}px)" srcset="{{ i.path }}, {{ sorted_sizes[0].path }} {{ sorted_sizes[0].width }}w, {{ sorted_sizes[onepointfive_x_res].path }} {{ sorted_sizes[onepointfive_x_res].width }}w, {{ sorted_sizes[two_x_res].path }} {{ sorted_sizes[two_x_res].width }}w, {{ sorted_sizes[threexres].path }} {{ sorted_sizes[threexres].width }}w" sizes="(min-width: 40em) 576px, (min-width: 64em) 720px, (min-width: 72em) 960px, 100vw">
{% endfor %}
<img src="{{ path }}">
</picture>