Cloudinary Blog

How I used Cloudinary to solve responsive image needs in my Jekyll website, and shared the magic in a plugin

By Nicolas Hoizey
Plugin for Automatic Responsive Image HTML Code Generation

This is a guest post by Nicolas Hoizey, co-founder of Clever Age and creator of the Jekyll Cloudinary plugin. Nicolas’ plugin leverages Cloudinary’s image storage, optimization, resizing, and delivery infrastructures to automate responsive images in Jekyll-generated static sites. We think it’s the bee’s knees, and invited Nicolas to write a bit about the process and motivation behind it. Without further ado, here’s Nicolas.

I recently migrated my personal website to the latest major version of Jekyll, and took the opportunity to re-think my toolchain.

Some of the plugins that I’d been using were not satisfying my needs for responsive images, so I decided to find other ways to fulfill these needs.

To generate the responsive images HTML (do I really need to say that using native responsive images should be a no-brainer nowadays?), I tried the Jekyll Responsive Image plugin. It is really nice; it lets you define your own image markup templates, which means you can use srcset or <picture> as you like. But it didn’t address all of my concerns:

  • Generating a Jekyll site from scratch with this plugin requires generating all images’ variants from the master images. I currently have around 750 images on my blog, leading to some very long build times.
  • Sending all these variants to the server also takes quite some time, because I don’t have fast network access at home.
  • And of course, all these images are served from the same server as the pages, which in my case is cheap (but nice) shared hosting.

I wanted a simplified and faster workflow, and less load on the server side.

Most of the responsive web sites that my company builds for clients use ad-hoc solutions for responsive images, but I was aware of a few SaaS responsive image solutions, so I decided to check if any of them would fit my needs.

Cloudinary is one of the most feature-rich solutions available, and it can even be used for free if your needs are reasonable. It's not easy for other solutions to compete with that…

With a free account, I could test whatever I wanted, try different features, and decide to continue or look elsewhere.

The main features I was looking for, which Cloudinary provides, are:

  • The ability to use the service as a proxy: the master images are stored on my hosting, but all images delivered to my visitors come from Cloudinary, generated on the fly from the masters. Even better, I don’t need to manually upload the master images – Cloudinary fetches them automatically from my local, published versions. In other words, the only “client” for my originals is Cloudinary. As a result, the bandwidth for images on my hosting is really low.
  • Image cropping and resizing options: right now, I am only scaling my images down from large masters to fit responsive layouts. But I’m definitely looking at the possibility of doing advanced art direction using Cloudinary’s magical automatic cropping features.
  • Image format optimization: if I publish JPEG images in my posts, Cloudinary can send WebPs to visitors if their browser supports them. Last month, two thirds of the images delivered by Cloudinary to my visitors were WebPs, which Cloudinary generated and served for me, automatically. That’s a huge win for both my visitors’ performance and data plans, and for my Cloudinary bandwidth quota.
  • Image compression optimization: Cloudinary is able to compute the best compression level to lower the weight of each image while keeping the visual quality high.

Convinced that Cloudinary offered everything I needed, I still had to develop a Jekyll plugin that used these features.

After some consideration, I decided to start with a {% cloudinary %} Liquid tag that would ease image publication with Cloudinary, while still being relatively easy to develop. I took inspiration from other plugins, found help on StackOverflow when needed, and finally released the first version of the Jekyll Cloudinary plugin in July 2016.

The syntax is pretty straightforward:

Copy to clipboard
{% cloudinary [preset] path/to/img.jpg alt="alt text" caption="image caption" %}

From this input, the plugin outputs responsive image HTML, using the srcset and sizes attributes for the <img> tag (see the “varying size and density” section of this post to understand how these attributes work, and this post which explains why you should use them instead of <picture>, most of the time). The srcset and fallback src contain Cloudinary URLs that fetch the post’s master images on-the-fly and resize them to several, alternate sizes.

For example, as shown in the documentation, this code in a Markdown file:

Copy to clipboard
{% cloudinary logo /assets/logos/cloudinary.png alt="Cloudinary logo" %}

will generate this HTML code:

Copy to clipboard
<img
  src="https://res.cloudinary.com/<cloud_name>/image/fetch/c_limit,w_480,q_auto,f_auto/https://<domain>/assets/logos/cloudinary.png"
  srcset="
    https://res.cloudinary.com/<cloud_name>/image/fetch/c_limit,w_80,q_auto,f_auto/https://<domain>/assets/logos/cloudinary.png 80w,
    https://res.cloudinary.com/<cloud_name>/image/fetch/c_limit,w_240,q_auto,f_auto/https://<domain>/assets/logos/cloudinary.png 240w,
    https://res.cloudinary.com/<cloud_name>/image/fetch/c_limit,w_400,q_auto,f_auto/https://<domain>/assets/logos/cloudinary.png 400w"
  sizes="
    (min-width: 50rem) 13rem,
    (min-width: 40rem) 25vw,
    45vw"
  class="logo"
  alt="Cloudinary logo"
  width="480"
  height="350"
/>

You are in full control of the number of generated images, their resolutions, and the sizes attribute (which helps the browser decide which image to download). This control comes from the configuration options you can use in your _config.yaml. Here is the part of my configuration file where I defined rules for logos:

Copy to clipboard
cloudinary:
  cloud_name: 
  presets:
    logo:
      min_width: 80
      max_width: 400
      fallback_max_width: 200
      steps: 3
      sizes: '(min-width: 50rem) 13rem, (min-width: 40rem) 25vw, 45vw'
      figure: never
      attributes:
        class: logo
  • cloud_name: … is your personal ID from Cloudinary
  • presets: starts the list of presets you define for your site
  • logo: is the name of one of my presets, which I use in the Liquid tag before the name of the image file
  • min_width: 80 defines the narrowest generated image
  • max_width: 400 defines the widest generated image
  • fallback_max_width: 200 defines the fallback (src) image width
  • steps: 3 defines the number of images to generate
  • sizes: '(min-width: 50rem) 13rem, (min-width: 40rem) 25vw, 45vw' defines the sizes attribute of the responsive image, which depends on the design and breakpoints
  • figure: never prevents generation of a full <figure>/<img>/<figcaption> element (I often don't want them on logos)
  • attributes: starts a list of attributes to always add to generated <figure> and/or <img> elements
  • class: logo adds a class attribute with a logo value, which I use in my CSS to make sure the logo never takes more than one fourth of its container width, and is floated right

You can define all of these rules, for any number of presets that you need.

With this plugin and my free Cloudinary account, the build time of my site has been reduced by 90%, the storage on my server has been reduced by 60%, and I don't have to worry about image optimization anymore. Huge wins.

Where to go from here? Originally, I wanted to allow writers to use the simple standard Markdown syntax for images, but I have not managed to build this yet, despite some valuable answers to my questions from Jekyll lead maintainer Parker Moore himself. I'll have to dig deeper into Jekyll hooks in the future.

At the end of the day, this was a great way to learn a bit of Ruby, a bit about the Jekyll internals, how plugins work, and how to build and release a gem… I’ve learned so much in a short period of time thanks to this useful little pet project.

Of course, help is welcome to make the plugin even better. There are already a few issues open for bugs or things that should be added to the plugin. Feel free to add your bug reports and ideas, or even contribute through pull requests!

Further Reading on Responsive Images

Recent Blog Posts

New Learning Pathways From the Cloudinary Academy

In December 2019, Cloudinary launched its customer education platform, the Cloudinary Academy, replete with courses taught by the company’s experts on developer-oriented products and digital asset management (DAM) solution. The courses comprise interactive lessons and hands-on assignments, a proven way of familiarizing the audience with the course material and illustrating it with live examples.

Read more
Maya Shavin: How I Built My Website

Besides working as a senior front-end developer at Cloudinary, I'm also a content creator, a blogger, and an open-source developer. Follow me at @mayashavin and on mayashavin.com.

In the beginning, my website, mayashavin.com, was mainly for showcasing the status of my development projects and keeping me organized with my speaking schedule. Initially, I built it with Vue.js, later on switching to Nuxt.js (aka Nuxt) for a higher SEO score, and deployed it with Netlify. After some time, I added a blog section with Netlify CMS as the content management system (CMS). Everything was fine until I added more content and features, which led to a significant decline in the site’s performance. Also, the site design needed a modern look. So, I gave the site a makeover.

Read more
Automation Frees Up PetRescue’s Staff to Help Pets Find Their Forever Homes

As we spend more time at home, many of us are adopting pets for the joy, companionship and a surprising range of health benefits. In Australia, where our nonprofit customer PetRescue is located, there’s a shortage of pets to adopt. Last August, the Guardian reported that dog shelters in Australia emptied and adoption fees for puppies were running as high as $AUS1800.

Read more
Cloudinary and Contentful Make Modern Content Management Easier

I am pleased to share that Cloudinary and Contentful have joined forces to further streamline the creation, processing, and delivery of online content through Cloudinary’s digital asset management (DAM) solution and advanced transformation and delivery capabilities for images and video. What’s more, the partnership delivers a headless approach to DAM. By leveraging APIs for media management tasks, marketers and developers alike benefit from an integrated stack of optimized assets for optimization and automation. As a result, page loads are fast and beautiful, and at scale—with less overhead and effort.

Read more
Introducing Cloudinary's Nuxt Module

Since its initial release in October 2016 by the Chopin brothers as a server-side framework that runs on top of Vue.js, Nuxt (aka Nuxt.js) has gained prominence in both intuitiveness and performance. The framework offers numerous built-in features based on a modular architecture, bringing ease and simplicity to web development. Not surprisingly, Nuxt.js has seen remarkable growth in adoption by the developer community along with accolades galore. At this writing, Nuxt has earned over 30K stars on GitHub and 96 active modules with over a million downloads per month. And the upward trend is ongoing.

Read more