Responsive images questions

My website has several case studies. The case studies have a lot of images. They appear full width, in a single column. The column has a max-width of 2112px.

I have a snippet called image.php

<img
	alt="<?= $file->alt() ?>"
	class="<?= $file->border() ?>"
	src="<?= $file->url() ?>" 

	srcset="<?= $file->srcset(
		[
			'600w'  => ['width' => 600],
			'1024w'  => ['width' => 1024],
			'2112w' => ['width' => 2112],
		]
	)?>"
	width="<?= $file->resize(2112)->width() ?>"
	height="<?= $file->resize(2112)->height() ?>"
>



<?php if ($file->caption()->isNotEmpty()): ?>
	<p class="caption"><?= $file->caption() ?></p>
<?php endif ?>

I can see in the browsers Dev Tools that at viewport 600px and 1024px that different, smaller file size, images are being used. So it works! But…

My original files are 3240px wide. Taking one file as an example. The original file size is 179kb. But the 2112px version is considerably larger at 461kb. This can’t be right?

On a large monitor, with a high Device Pixel Ratio, like a 24 inch iMac, the most appropriate image file would be the original images 3240px wide. The 2112 images won’t look so good on a screen with a DPR of 2. But how do I call in my 3240 images?

What does this bit of the code do?

width="<?= $file->resize(2112)->width() ?>"
height="<?= $file->resize(2112)->height() ?>"

Thanks!

This can indeed happen, depending on the image Which thumbs driver are you using? It would make sense to use modern image formats as well.

You can’t with srcset, because srcset always creates thumbs. So you would have to create a thumb as large as the max size to fit this into the srcset. Not sure if the browser would fall back to the src attribute in this case, because there you already use the original image.

It outputs the width and height values of the (largest) thumb, in this case. The purpose of adding the width and height attributes is not so much their exact values but the ratio, so as to prevent layout shifts. You can read up on this in the Google Lighthouse details.

Which thumbs driver are you using?

I have no idea what that means

It would make sense to use modern image formats as well.

Yep, I’m going to get to that once I’ve got the responsive images working.

You can’t with srcset, because srcset always creates thumbs.

Always creates thumbs - what’s a ‘thumb’? srcset always creates a (smaller) version of the original image - and that is called a ‘thumb’? Is that short for thumbnail – a smaller version of a larger image?

So you would have to create a thumb as large as the max size to fit this into the srcset

So if the max-width is 2112px and to cater for devices with a DPR of 2, would I add the following

'4224w' => ['width' => 4224],

From a previous question I understand the srcset does not upscale images. So, would it use the original (3240px image)?

It outputs the width and height values of the (largest) thumb, in this case. The purpose of adding the width and height attributes is not so much their exact values but the ratio, so as to prevent layout shifts.

Is this code for square ratio images 2112 x 2112? most of my images are 2:1 ratio, but not all. My largest thumb will be 4224 or 3240? What should I do here?

No, the thumb resulting from resize(2112) is not square, but keeps the original ratio.

Exactly, therefore you should use the original image size as maximum size, with you get from $file->width().

Exactly, therefore you should use the original image size as maximum size, with you get from $file->width().

I don’t understand. Would I use the following code:

'600w'  => ['width' => 600],
'1024w'  => ['width' => 1024],
'2112w' => ['width' => 2112],
'3240' => ['width' => 3240],

I’ll look into what “thumbs” means. Thanks for the link

Would the generated thumbs be so much larger than the original file because I am only testing locally using MAMP? At the moment the bigger file sizes negate the whole point of using responsive images.

What is a thumb?

A thumb in the context of Kirby is the result of a manipulated source image.

Thumb as in Thumbnail.

You have the thumb file method aswell which allows you to do things like crop, resize, grayscale etc

1 Like

I now have the following code:

<img
	alt="<?= $file->alt() ?>"
	class="<?= $file->border() ?>"
	src="<?= $file->url() ?>" 

	srcset="<?= $file->srcset(
		[
			'600w'  => ['width' => 600],
			'1024w'  => ['width' => 1024],
			'2112w' => ['width' => 2112],
			'3240w' => ['width' => 3240],
		]
	)?>"
	width="<?= $file->resize(3240)->width() ?>"
	height="<?= $file->resize(3240)->height() ?>"
>



<?php if ($file->caption()->isNotEmpty()): ?>
	<p class="caption"><?= $file->caption() ?></p>
<?php endif ?>

But the responsive image file sizes are often larger than the original image.

For example:

a PNG image
Original size 3240px = 179 kb
3240 thumb = 523 kb
2112 thumb = 461 kb
1024 thumb = 135 kb
600 thumb = 55 kb

a JPG image
Original size 3240px = 230 kb
3240 thumb = 459 kb
2112 thumb = 460 kb
1024 thumb = 142 kb
600 thumb = 58 kb

As I don’t know what it is I’m using the default Thumbs driver.

The larger image files makes the point of doing this somewhat redundant – unless I can claw back the extra KB converting the images to modern image formats. But that feels like one step backwards and one step forwards.

Yes, as I already mentioned above, if your original files are already very compressed, this can happen. What you can try is check if you can use the im (ImageMagick) thumbs driver, if the ImageMagick is available on your server (see documentation linked above).

And/or play around with image formats and the quality settings (using the thumb() instead of the shortcuts like resize().

As someone who builds alot of portfolio / image heavy sites, i can share my own personal workflow, if it helps:

  1. Export the source image from your graphics program and 100% Jpeg for photos. PNGs should be for graphics like logos and charts. Personally I use images not more than 2,000px wide.
  2. Run the images through ImageOptim (on a mac ImageOptim — better Save for Web ) or Optimize Images (cross platform python script optimize-images · PyPI)
  3. Use ImageMagick if you can on the server, as it yeilds better results in my experience
  4. From there use Kirby srcset / thumb methods as appropriate.
  5. Make use of WebP and Avif if your server allows.

I find that way i get good quality images, and usually 100% score in Chrome Lighthouse.

1 Like

Hey, thanks.

Can I check a few things

Export the source image from your graphics program and 100% Jpeg for photos.

Do you mean all photos should be JPEG. Or, that when saving JPEGs the compression should be 100% (no compression)?

Run the images through ImageOptim (on a mac [ImageOptim — better Save for Web]

So you don’t use Photoshop Save for Web but instead use ImageOptim?

So basically your original image has no JPEG compression and only non-lossy ImageOptim compression – so that the original image is incredibly high quality.

(I thought the thing to do was use images at double the size that they are to be used at – for retina screens – and then compress the hell out of them. The result is actually quite small file sizes. It turns out considerably smaller than the generated responsive thumbs)

Broadly speaking, yes. If its a camera photo it should be a JPEG (or WebP or AVIF). PNGs are not suited to photos really due to the high file size. The gotcha there is images with gradients or stuff like smoke or fire. You might find you end up with artificats because Jpegs dont have a bit depth large enough to display that properly. Youll see noticable banding if you go to hard on the compression.

Personally i use Affinity Photo but most graphics programs have a sliding quality scale like below when you do a normal Jpeg export. Just crank it right up.

Not quite i DO do lossy compression with ImageOptim, i just go easy on it, and it compare results. If non-lossy isnt a crazy file size, i use that. If im using that Python script instead, i just let the defualts do its thing.

1 Like

My server has the option to use ImageMagick. For now I am testing locally on my Mac using the MAMP app. I think I am using ImageMagick, but the file sizes of the thumbnails is the same as previously.

My site > config > config.php file contains the following code (this is all of it). Is this written correctly?

<?php

return [
    'debug'  => false
];

return [
  'thumbs' => [
    'driver' => 'im'
  ]
];

My images are stacked one on top of the other in a single column. The column has a small bit of left and right padding. The column has a max-width of 2112px.

I have the code to create thumbnails that are various widths up to 2112px wide. These are based on the width of the viewport. This seems fine.

When the viewport is wider than 2112px (and the screen has a Device Pixel Ratio of 1), then it is fine for the 2112px width images to be served. But what happens when the viewport is wider than 2112px and has a DPR of 2 (for example large retina screens)? What code would I need to get my original images at 3240px to be served?

This is my code so far

<img
	alt="<?= $file->alt() ?>"
	class="<?= $file->border() ?>"
	src="<?= $file->url() ?>" 

	srcset="<?= $file->srcset(
		[
			'600w'  => ['width' => 600],
			'1024w'  => ['width' => 1024],
			'2112w' => ['width' => 2112],
		]
	)?>"
	width="<?= $file->resize(2112)->width() ?>"
	height="<?= $file->resize(2112)->height() ?>"
>

Your second return statement won’t have any effect, please see Configuration | Kirby CMS

Will this work?

<?php

return [
  'debug'  => false,

  'thumbs' => [
    'driver' => 'im'
  ]
];

The images appear to be the same size as using the default thumb driver (I’m testing locally, I don’t know if that makes any difference)

First of all, you need to test if ImageMagick is present on your machine. On the command line, type:

which convert

On my system, this gives me

/opt/homebrew/bin/convert

Since this path is not the standard path to the binary, I would have to add this path in Kirby’s config file, like explained in docs I already linked above: thumbs | Kirby CMS

If you get an error message, the binary does not exist.

You also need to make sure that your server allows PHP to use executing the exec() function, which you can check in your php.ini. On localhost, this should usually be possible (you never know until you verify), but on your remote server, you need to check in any case.

There are a couple of useful commands on this page you can run on the server to see if the version installed can handle AVIF and/or WebP

if i do:

php -i | grep AVIF

i get:

AVIF Support => enabled
ImageMagick supported formats => 3FR, 3G2, 3GP, AAI, AI, APNG, ART, ARW, ASHLAR, AVI, AVIF, AVS, BAYER, BAYERA, BGR, BGRA, BGRO, BMP, BMP2, BMP3, BRF, CAL, CALS, CANVAS, CAPTION, CIN, CIP, CLIP, CMYK, CMYKA, CR2, CR3, CRW, CUBE, CUR, CUT, DATA, DCM, DCR, DCRAW, DCX, DDS, DFONT, DNG, DOT, DPX, DXT1, DXT5, EPDF, EPI, EPS, EPS2, EPS3, EPSF, EPSI, EPT, EPT2, EPT3, ERF, EXR, FARBFELD, FAX, FF, FILE, FITS, FL32, FLV, FRACTAL, FTP, FTS, FTXT, G3, G4, GIF, GIF87, GRADIENT, GRAY, GRAYA, GROUP4, GV, HALD, HDR, HEIC, HEIF, HISTOGRAM, HRZ, HTM, HTML, HTTP, HTTPS, ICB, ICO, ICON, IIQ, INFO, INLINE, IPL, ISOBRL, ISOBRL6, J2C, J2K, JNG, JNX, JP2, JPC, JPE, JPEG, JPG, JPM, JPS, JPT, JSON, JXL, K25, KDC, KERNEL, LABEL, M2V, M4V, MAC, MAP, MASK, MAT, MATTE, MEF, MIFF, MKV, MNG, MONO, MOV, MP4, MPC, MPEG, MPG, MRW, MSL, MSVG, MTV, MVG, NEF, NRW, NULL, ORA, ORF, OTB, OTF, PAL, PALM, PAM, PANGO, PATTERN, PBM, PCD, PCDS, PCL, PCT, PCX, PDB, PDF, PDFA, PEF, PES, PFA, PFB, PFM, PGM, PGX, PHM, PICON, PICT, PIX, PJPEG, PLASMA, PNG, PNG00, PNG24, PNG32, PNG48, PNG64, PNG8, PNM, POCKETMOD, PPM, PS, PS2, PS3, PSB, PSD, PTIF, PWP, QOI, RADIAL-GRADIENT, RAF, RAS, RAW, RGB, RGB565, RGBA, RGBO, RGF, RLA, RLE, RMF, RW2, SCR, SCT, SFW, SGI, SHTML, SIX, SIXEL, SPARSE-COLOR, SR2, SRF, STEGANO, STRIMG, SUN, SVG, SVGZ, TEXT, TGA, THUMBNAIL, TIFF, TIFF64, TILE, TIM, TM2, TTC, TTF, TXT, UBRL, UBRL6, UIL, UYVY, VDA, VICAR, VID, VIFF, VIPS, VST, WBMP, WEBM, WEBP, WMV, WPG, X3F, XBM, XC, XCF, XPM, XPS, XV, YAML, YCbCr, YCbCrA, YUV

which means both imagemagic and GD support avif. you can tweak the command for Webp too.

Worth pointing out there that you will like need to use multi site configs to set the bin to different paths locally and on the live site. I also have convert installed via home brew so need to do this too.

in my local config.php i have

'thumbs' => [
  'driver' => 'im',
  'bin' => '/opt/homebrew/bin/convert'
],

but on live config.domain.com.php this needs to be

'thumbs' => [
    'driver' => 'im',
    'bin' => '/bin/convert'
],

You can find more about multi environment based configs here:

I’ve contacted my host and they inform me that ImageMagick is on my server. So assuming the following code is correct, ImageMagick should work on my server without having to do anything else like changing paths to the binary (I have no idea what that means, so I really don’t want to have to change it)?

<?php

return [
  'debug'  => false,

  'thumbs' => [
    'driver' => 'im'
  ]
];