Basic understanding and several questions around srcset and kirby

Hi all,

I’m having trouble to understand some basic concepts about how srcset and Kirby work together and didn’t find this information here or in the references, could you please help me understand or correct?

  1. So far I understood that the image driver creates the thumbs when defined in the config and stores them in the media folder. When does this process happen? In my case it only affects images I’ve uploaded via the panel, but not the ones in the content folders (I also can’t access those via the panel, or is that another problem?). Sorry, update: it also creates the thumbs for the images I can’t access via the panel, but also other sizes that weren’t defined by me (I’ve completely emptied the media folder already)
    But so far I at least got this to work.

  2. How would I go about it if I wanted to create the thumbs myself via photoshop batch processing, would I then store the asset sets in the content folders? And how would I refer/loop through them and at the same time letting the browser choose the appropriate size via PHP?

  3. I have a standard photo portfolio with a grid showing cover images in an overview (where I used the normal srcset and sizes, which seems to work well, here: Work) and single project pages with a very granular grid, so I can exactly place the child images via specific project related css using nth (I haven’t placed the children yet, so it still looks weird, here: Project A).

For the latter I would love to use the autosize method and was trying to access it with bnomeis plugin. So far I think I didn’t get it to work. Is it correct that also in this case the scrset thumbs would be created and the browser would choose the correct size in this case provided by the granular grid (columns are defined with vw). In that case I would find the appropriate thumbs when testing the page with dev tools, not the original file name, right? Do I have to use „lazysrcset“ for the definitions in the config or just srcset?

  1. And this is not related to srcset, but to the grid on the single pages. Is there a way to change the background colour of single rows of the grid? Div with another z-Index?? The rows are 100vh.

I’ve read a ton here, but I’m only getting more confused… or is there more explanation to these subjects somewhere and I just didn’t find it?

Thanks in advance!

Hi Carola,

Ad 1)
the thumbs are created when the URL to an image is called.

You can either set predefined thumb and srcset sizes in the config or call sizes using the thumbs(), resize() and crop() methods with the desired parameters.

In addition to the sizes you define, the Panel creates the thumbs it needs to display images in files view or the sections.

If you upload files outside of the Panel, it might be that they don’t get display in the Panel if your files sections/fields are limited to a template. If you just put a file into a content folder manually, it doesn’t get that template applied and thus doesn’t show up.

ad 2)

Custom thumbs can of course be created and uploaded. I’m not sure what is the best way to go about this, maybe connect them by filename and then assign these files to the appropriate srcset sizes (without using Kirby’s thumb() or srcset()` methods, but creating the srcset manually.

Hi @pixelijn,

thanks so much for your answer!

Okay, this explains the extra image formats, thanks!

I don’t completely understand this, I thought it all connects automatically when all elements (blueprint, template…) have the same file name. How would I “apply” a template to files in a content folder? Because it is a photography page, it would be quite a lot of work to upload single files.

I’m just confused about how to write this having the extension in mind.

I think that this is my problem, because I need to automate it as there are a lot of images and since they are also in portrait and landscape format, they will be showcased in very different width, like fe 60vw vs 33vw. But the more I think about it I probably makes more sense to try and get the autosizing of the plugin to work.

Yep, that sounds like trouble if you do that manually.

Can’t help you with the plugin, haven’t used it myself. Maybe @bnomei has some tips for you?

Thanks, @texnixe, and that would be awesome if @bnomei could give me some tips, as I’ve been fiddling around for hours…

Do you have any idea of 4) is possible? I don’t expect code, just your opinion;-)

Plugin: I followed the instructions to my best knowledge (so far putting the plugin in the appropriate folder, defining srcsets in the config, adding lazysizes.min.js and adding the Minimal CSS), but don’t really know how to translate it into my template. So far I’ve been using only srcset and not lazysrcset together with sizes=“auto”, which kinda works, but not really, as Lighthouse claims that I’m using “images with inappropriate size”, but in that case half of the expected size, so not considering retina.

And I’m mostly confused about how everything works together (lazysrcset instead of srcset, data-src instead of src). And do I have to somehow tell Kirby that I want to use the plugin or is having it in the folder enough?

I don’t know if that’s appropriate here, but I wouldn’t mind a quote for a setup of the plugin either, because let’s face it, I don’t know what I’m doing yet :smiley:

I’m not quite sure what you mean?

The plugin is loaded once you put it into the folder. Everything else depends on what the plugin readme tells you to do (config settings, loading scripts/stylesheets).

But aFarkas/lazysizes, the library used by the plugin, should actually do it’s job out of the box, provided you set the options correctly.

The problem is that many things described in here aren’t clear for me. And I’ve read it many times by now, also the readme of lazysizes. I would love to be able to simply follow the readme…
I have setup the config settings, loading scripts/stylesheets, but then I fail to translate this properly into PHP. And in the end I want to work with Devs, not become one…

Bnomeis readme says, if I understand it correctly to define srcsets and then use lazysrcset. I’m having a foreach looping through my project images and tried to call it like so:

srcset="<?= $image->lazysrcset('default');

and in many other variations, because at the moment it’s just trial and error for me. And then I already don’t know if this should be “data-srcset” instead. And would I have to define “data-srcset” separately in the config or does it automatically use the srcset options?

I have now followed some of the instructions of aFarkas/lazysizes using data-sizes=“auto” and “data-srcset”, together with the described CSS rule for the image for the width definition, because automatically setting the sizes attribute only works when the width is set. Since I’m spanning my images into columns, the width should be definable for the browser. This seems to work except for retina etc.

But I thought I wouldn’t need to use x-descriptors in the config when I’m going for a viewport-based selection, but the output for retina isn’t correct yet. Or do I?

The main thing I want to achieve is that the browser chooses the perfect image size for the images and their specific width is defined by the grid columns.

hi @neongrau, my plugin does create a full img element not the string for srcset attribute like the kirby core kirby function does. to get it running you need the following steps:

  1. have all the css from the plugin readme and link the file in your html
  2. js lazysizes loaded after the css (like css in head and lazysizes just before closing body)
  3. call echo $image->lazysrcset(); to generate the img element

my plugin does use the srcset definitions for your config BUT only the most simple version of a plain one-dimensional array of integers. it can not handle the more complex options (since they did not exist when i created the plugin, not even the core srcset function did exist back then).

Hi @bnomei,

thanks for answering, much appreciated.

Yes, I did steps 1 and 2 (to my best knowledge), but didn’t know how to go further, as I’m having a foreach loop and a figure element with a class already. I remembered it kinda worked when I muted the new figure element with figure false, but I still had text showing under the pictures, which probably were just coding errors from me. But when I understand you well I anyway can’t use the plugin for my use case, right?

I’ve been trying the autosizing of the lazysizes-plugin now described under "responsive image with srcset and automatic sizes attribute“ here, and it seems to work, only not for retina. I’m not exactly sure how the auto sizes work, maybe I still have to define the x-descriptors in the config, like 3 different sets for 1x, 2x, 3x? Do you maybe know that?

Or what is the best practice as for now to deal with responsive images and retina in Kirby for looped images in different sizes? I’m quite lost at the moment and since it’s a photography page, this part is crucial… :slight_smile:


Hi Sonja,

about 4)

It’s not that important, I first need to get my image quality right…

But what I had in mind as output was the following: I’m looping through my project showing only one image per full screen (100vh) in a grid with many columns, but only one row (100vh). I was thinking of changing the colour of the background for each picture.

I thought that it would maybe be possible to create one div (z-1) for each image (z-2) in the loop, span it over the full row and change the colour via the custom css template as the div would be related to the specific nth child image.

But it sounds already to complicated to explain and way out of my league…

So for now I would be really happy if you could maybe help to shed some light on the responsive/retina problem above.

How can I set the options right in the config for that the browser knows which image to use for retina?

My config looks like this at the moment:

return [
'debug' => true,
'thumbs' => [
  'srcsets' => [
    'default' => [
      '320w' => ['width' => 320, 'quality' => 80],
      '614w' => ['width' => 614, 'quality' => 80],
      '820w' => ['width' => 820, 'quality' => 80],
      '960w' => ['width' => 960, 'quality' => 80],
      '1152w' => ['width' => 1152, 'quality' => 80],
      '1280w' => ['width' => 1280, 'quality' => 80],
      '1536w' => ['width' => 1536, 'quality' => 80],
      '2048w' => ['width' => 2048, 'quality' => 80],
      '2304w' => ['width' => 2304, 'quality' => 80],
      'breakpoints' => [480, 768, 992],
      'interlace' => true,


Thanks so much!

Don’t worry about retina, the browser will pick what’s right. Lighthouse is probably running with a lower DPI and therefore picking the non- retina size. You may want to add a few more sizes, however, as there are some 6K displays on the market, so around 5800 pixels wide.

For srcset to work you need both the config you have above and a size attribute. If you omit it, 100vw will be assumed when checking which image to choose.

You may find that reducing the quality slightly for very retina images is acceptable. If you want to create a set of sources to use on retina displays, you’ll need to use the picture element.

1 Like

But using @bnomei’s plugin and the lazysizes option set to data-sizes="auto" you shouldn’t have to worry about setting these manually.


Hi @mxdvl and @texnixe,

thanks for taking the time to answer again.

Yes, it’s like @texnixe said, the lazysizes used with data-sizes="auto" autocalculates the sizes based on viewport and width indicators. In my case, I’m using a granular grid (24x3.33vw plus padding on both sides) and spanning my looped images over it (fe: span 10 = 33,3 vw). This should give the browser enough indication to calculate the size for the specific picture and that’s why I thought that I didn’t need to use the picture element. And since it’s a photography page, I don’t want to artdirect anything, just show the pictures as they are in their best quality.

I’m not sure if I still need to do ratio calculations for the height like mentioned in the lazysizes manual or if it already works. Is there another way to understand if it works other than Lighthouse? What worries me is that when I look at the code the data-src is empty, so I’m probably doing something wrong.
For example: the first picture here spans over 10 columns = 33,3 vw which on a 1440px-screen is 479px. The picture loaded as seen in Lighthouse is the 614w-version, which should be the 960w-version for a retina display. Right? Or how can I find out if Lighthouse is running with a lower DPI?

I’ve tried to do it like described here under „HOW TO“, point 2, responsive. I’m not using bnomeis plugin anymore, only lazysizes, as it should do the trick alone.:

And this is my code, am I calling it wrong?

<ul class="projectgrid">
<?php foreach($page->images()->sortBy('sort') as $image): ?>
  <figure class="imageholder">
    alt="<?= $image->alt() ?>"
    data-src="<?= $image->srcset(320) ?>"
    data-srcset="<?= $image->srcset([320, 614, 820, 960, 1152, 1280, 1536, 2048, 2304]) ?>"
    class="lazyload" />
<?php endforeach ?>

The data- prefix is read by JS and will then inject these attributes without the prefix. This is so lazy loading works, otherwise your browser will start downloading the image as soon as it parses the DOM.

Once the page is loaded, you should only have the final attributes. You can check your network tab to see exactly which image was downloaded by your browser. Then resize it and reload the page: you should see a different image. You can also hover on the srcset to see which url was used, but I’ve found this a little bit unreliable and not consistent cross-browser.

Hope this helps! Responsive images are not the easiest in practice.

Thanks for spelling that out for me, got it.

This is exactly what I did to find out that the 614w-picture was used. When I resize to a very small viewport and reload, the 320w-version is loaded. So that works. Only I still think that it should be a bigger version for retina… Oh, or is the size not calculated on base of the actual screen, but on the size of the window that Chrome Dev tools uses? Then it actually works… Only still weird that there is nothing in “data-src” when looking at the source.

Update: I’ve put the network tab under the window now and now the expected 960w is loaded. So sorry! :see_no_evil:

1 Like

Yes, your viewport is based on your window size minus the dev tools.

If you actually look at the source code before JS modifies it, you should have a data-src value. You can also try temporarily disabling JavaScript.

1 Like

Yep, what a stupid error, it already worked all the time^^!

This didn’t work, somehow Javascript was always reactivated after reload. But I read the lazysizes manual again and when I want to use a LQIP (Low Quality Image Placeholder) technique, I only need to combine a low quality source together with the data-srcset. I’ll figure that out.

Thanks for you help, I learned something today, have a nice sunday!

1 Like

Hey :slight_smile:
a while ago i tried adding srcset with lazysizes and failed and then forgot about the topic.
Because the page is getting more and more traffic i need to have a look at this topic again.

So i copied everything from you @neongrau to the config and to my custom “image load block”

my custom block now looks like this:

<?php if ($image = $data->image_global_data()->toFile()) : ?>    
<picture width="<?= $image->dimensions()->width() ?>" height="<?= $image->dimensions()->height() ?>">
    <?php if ($webPImage = $site->image($image->name() . '.webp')) : ?>
      <source data-srcset="<?= $webPImage = $site->image($image->name() . '.webp')->url() ?>" type="image/webp">
    <?php endif ?>

    <?php if ($jpgImage = $site->image($image->name() . '.jpg')) : ?>
      <source data-srcset="<?= $jpgImage = $site->image($image->name() . '.jpg')->url() ?>" type="image/jpg">
    <?php endif ?>

    <?php if ($pngImage = $site->image($image->name() . '.png')) : ?>
      <source data-srcset="<?= $pngImage = $site->image($image->name() . '.png')->url() ?>" type="image/png">
    <?php endif ?>

    <img alt="<?= $image->alt() ?>" title="<?= $image->title() ?>"data-sizes="auto"  width="<?= $image->dimensions()->width() ?>" height="<?= $image->dimensions()->height() ?>" src="../../../../assets/images/placeholder.png"  data-src="<?= $image->srcset(320) ?>" data-srcset="<?= $image->srcset([320, 614, 820, 960, 1152, 1280, 1536, 2048, 2304]) ?>" class="lazyload">

So i try to use webp when possible and available and also want to use the srcset.

When i now have a look at the page it looks like it still is always picking the original.
Also in the media folder is only the original.

After removing my “choose webp or jpg” stuff it creates the the xsize files.
Sadly they are even getting bigger than the the originals…

Any idea?

You haven’t added data-src/data-srcset to the source elements…

You mean like that?

<?php if ($image = $data->image_global_data()->toFile()) : ?>
  <picture width="<?= $image->dimensions()->width() ?>" height="<?= $image->dimensions()->height() ?>">
<?php if ($webPImage = $site->image($image->name() . '.webp')) : ?>
  <source data-src="<?= $webPImage->srcset(320) ?>"data-srcset="<?= $webPImage = $site->image($image->name() . '.webp')->url() ?>" type="image/webp">
<?php endif ?>

<?php if ($jpgImage = $site->image($image->name() . '.jpg')) : ?>
  <source data-src="<?= $jpgImage->srcset(320) ?>"data-srcset="<?= $jpgImage = $site->image($image->name() . '.jpg')->url() ?>" type="image/jpg">
<?php endif ?>

<?php if ($pngImage = $site->image($image->name() . '.png')) : ?>
  <source data-src="<?= $pngImage->srcset(320) ?>" data-srcset="<?= $pngImage = $site->image($image->name() . '.png')->url() ?>" type="image/png">
<?php endif ?>

<img alt="<?= $image->alt() ?>" title="<?= $image->title() ?>"data-sizes="auto"  width="<?= $image->dimensions()->width() ?>" height="<?= $image->dimensions()->height() ?>" src="../../../../assets/images/placeholder.png"  data-src="<?= $image->srcset(320) ?>" data-srcset="<?= $image->srcset([320, 614, 820, 960, 1152, 1280, 1536, 2048, 2304]) ?>" class="lazyload">
<?php else : ?>

Doesnt seem to work.
it now only loads the original again

Also it show the size is the same as the image itself…