CraftCMS Template Based Image Transform for all the Sizes

I’ve been diving into Craft more and more lately, and love the way it handles template driven image transforms.

Quick background note: image transforms save everyone from uploading images at certain sizes. Craft lets you define rules that tranform images in a non-destructive way. So say you need a thumbnail that is 200px by 200px, you can set up an image transform that will create a cropped thumbnail from the original image without destroying that original image.

Craft has a great UI for creating image transforms in the admin, and they also allow these transforms to be created directly in the template file.

This allows developers to easily set an image transform that creates all image sizes needed for 2x and 3x capable devices. The major plus goes to the client as they only need to upload one 3x size image, and Craft handles the rest.

One way I like to handle this uses the picture element, like so:

<picture>
// set the image variable and get the image
{% set ImageVar = entry.photo.first() %}
// get the width of the image and divide it by 3
{% set baseWidth = ImageVar.getWidth() / 3 %}
// get the height of the image and divide it by 3
{% set baseHeight = ImageVar.getHeight() / 3 %}
// use the divided widths and heights to output the image
<img
srcset="
{{ ImageVar.getUrl({ width: baseWidth, height: baseHeight }) }} 1x,
{{ ImageVar.getUrl({ width: baseWidth*2, height: baseHeight*2 }) }} 2x,
{{ ImageVar.getUrl({ width: baseWidth*3, height: baseHeight*3 }) }} 3x"
src="
{{ ImageVar.getUrl({ width: baseWidth, height: baseHeight }) }}
"
alt="{{ ImageVar.title }}"
>
</picture>

Basically, all we’re doing is getting the image width and height, dividing it and then multiplying it again for the image output. So the client only has to upload one 3x size image and their job is done.

I’ve found this method to work well for me, but any feedback or suggestions are appreciated.

UPDATE - 3/21/17

I received some great feedback from Tim Knight. He was gracious enough to improve on my initial idea and share some code samples.

In an effort to make the code a little more readable, you could put all the image details in a single array:

{% set baseWidth = image.getWidth() / 3 %}
{% set baseHeight = image.getHeight() / 3 %}
{% set images = {
base: {
width: baseWidth,
height: baseHeight,
},
double: {
width: baseWidth * 2,
height: baseHeight * 2,
},
triple: {
width: baseWidth * 3,
height: baseHeight * 3,
}
} %}
<picture>
<img
srcset="
{{ image.getUrl(images.base) }} 1x,
{{ image.getUrl(images.double) }} 2x,
{{ image.getUrl(images.triple) }} 3x"
src="{{ image.getUrl(images.base) }}"
alt="{{ image.title }}"
>
</picture>

Again, thank you to Tim Knight for sharing this idea, and helping to make Medium a collaborative space.