Thumb array rule doesn't work

I want to provide the most optimized image version as possible by default without ignoring older browsers. That’s why I created the following code:

    <?php if($image = $article->image()): ?>
      <?php echo $image->thumb([
        [ 'width'   => 300, 'height'  => 200, 'quality' => 80, 'format' => 'avif'], 
        [ 'width'   => 300, 'height'  => 200, 'quality' => 80, 'format' => 'webp'], 
        [ 'width'   => 300, 'height'  => 200, 'quality' => 80, 'format' => 'jpg']
        ])->html(); ?>
    <?php endif ?>

With this code I just get the original image in full size instead of a thumb.
If I use this code instead I get a small .webp image, which is also the desired output but then no alternative image format is prepared:

    <?php if($image = $article->image()): ?>
      <?php echo $image->thumb([ 'width'   => 300, 'height'  => 200, 'quality' => 80, 'format' => 'webp' ])->html(); ?>
    <?php endif ?>

Did I understand something wrong or is the code not correct?
I am testing the Kirby version 3.6.0 Alpha 3 and I have the following code in my config.php:

    'thumbs' => [
      'presets' => [
        'default' => [
          ['width' => 1024, 'quality' => 80, 'format' => 'avif'],
          ['width' => 1024, 'quality' => 80, 'format' => 'webp'],
          ['width' => 1024, 'quality' => 80, 'format' => 'jpg']
        ]
      ],
      'srcsets' => [
        'default' => [
          '800w' => ['width' => 800, 'quality' => 80, 'format' => 'avif'],
          '800w' => ['width' => 800, 'quality' => 80, 'format' => 'webp'],
          '800w' => ['width' => 800, 'quality' => 80, 'format' => 'jpg'],
          '1024w' => ['width' => 1024, 'quality' => 80, 'format' => 'avif'],
          '1024w' => ['width' => 1024, 'quality' => 80, 'format' => 'webp'],
          '1024w' => ['width' => 1024, 'quality' => 80, 'format' => 'jpg'],
          '1440w' => ['width' => 1440, 'quality' => 80, 'format' => 'avif'],
          '1440w' => ['width' => 1440, 'quality' => 80, 'format' => 'webp'],
          '1440w' => ['width' => 1440, 'quality' => 80, 'format' => 'jpg'],
          '2048w' => ['width' => 2048, 'quality' => 80, 'format' => 'avif'],
          '2048w' => ['width' => 2048, 'quality' => 80, 'format' => 'webp'],
          '2048w' => ['width' => 2048, 'quality' => 80, 'format' => 'jpg']
        ]
     ]
    ],

You cannot pass multiple arrays to the thumb method and like that it wouldn’t make sense anyway.

If you want to provide multiple formats for the browser to choose, you need a picture tag with multiple sources

Thanks for the quick reply.
Does that mean that I cannot use the thumb feature of Kirby if I want to provide the best image format automatically but instead using the image function combined with srcset options?

Yes, you can, but not with a simple image tag and an array of arrays as arguments for the thumb() method.

You can either use the picture tag, of determine the right image format via accept headers on the server and then server the right image in an image tag.

Okay, understood. I thought the thumb helper would do the required steps by its own.
With this code I also get a bloated png instead of a small webp image:

    <?php if($image = $article->image()): ?>
      <img src="<?= $image->url() ?>" srcset="<?= $image->srcset([ 'width'   => 300, 'height'  => 200, 'quality' => 80, 'format' => 'webp' ]) ?>" />
    <?php endif ?>

Why would you expect a webp image here? And I think it doesn’t make sense to have a src image as png and a srcset image as webp.

Based on the description of the 3.6.0 Alpha I understood that it is possible to define a set of srcset options in an order that automatically selects the most optimized version based on the browser capabilities:


That is why I have defined the following default settings in the config.php:

    'thumbs' => [
      'quality' => 90,
      'autoOrient' => true,
      'presets' => [
        'default' => ['width' => 2048, 'quality' => 90],
        'blog' => ['width' => 1000, 'quality' => 85],
      ],
      'srcsets' => [
        'default' => [
          '800w' => ['width' => 800, 'quality' => 80, 'format' => 'avif'],
          '800w' => ['width' => 800, 'quality' => 80, 'format' => 'webp'],
          '800w' => ['width' => 800, 'quality' => 80, 'format' => 'jpg'],
          '1024w' => ['width' => 1024, 'quality' => 80, 'format' => 'avif'],
          '1024w' => ['width' => 1024, 'quality' => 80, 'format' => 'webp'],
          '1024w' => ['width' => 1024, 'quality' => 80, 'format' => 'jpg'],
          '1440w' => ['width' => 1440, 'quality' => 80, 'format' => 'avif'],
          '1440w' => ['width' => 1440, 'quality' => 80, 'format' => 'webp'],
          '1440w' => ['width' => 1440, 'quality' => 80, 'format' => 'jpg'],
          '2048w' => ['width' => 2048, 'quality' => 80, 'format' => 'avif'],
          '2048w' => ['width' => 2048, 'quality' => 80, 'format' => 'webp'],
          '2048w' => ['width' => 2048, 'quality' => 80, 'format' => 'jpg']
        ]
     ]
    ],

Now when I add an image in a template like this:

<img src="<?= $image->url() ?>" srcset="<?= $image->srcset() ?>" />

I would expect that the src is pointing to the original file and the srcset will offer the specified srcset formats from which the browser then can automatically select the best one.
Doesn’t this also support the automatic generation of other file formats such as avif or webp?

I’d say the docs are misleading here.

This array doesn’t make sense, anyway, because you cannot use the same key multiple times.

And as I said above, srcset is for different resolutions at different sizes, not for serving multiple image formats.

I’d say this is a testament to how confusing the specs around srcset, sizes, source (with and without type; with and without srcset) and picture are.

I mean, Bastian isn’t exactly a newbie in regards to web development

Your options are therefore:

  • Use the picture tag with different <source> elements per image format
  • Or: Determine the accepted image format and serve this format in your <img> tag

Definitely not. I guess that was just a short form of showing alternatives.

Thanks a lot for clarification, now I fully understood it (I guess).
I wish there would be a cookbook recipe for integrating optimized images with all these options available but I will try to combine the mentioned things in a tag and give it a try.

So I tried to build the picture tag with multiple sources but I get an error 500 in Kirby if I integrate it. What have I missed?

​<picture>
 <source srcset="<?= $image->thumb(['format' => 'avif'])->url() ?>" type="image/avif">
 <source srcset="<?= $image->thumb(['format' => 'webp'])->url() ?>" type="image/webp">
 <source srcset="<?= $image->thumb(['format' => 'jpg'])->url() ?>" type="image/jpeg">
 <img src="<?= $image->url() ?>" alt="">
</picture>

A 500 error is a server error that should be unrelated to this code. Please check if you find something in your error logs.

I assume $image is correctly defined.

I have put the picture tag in a snippet that I am referencing from my blog template. In the blog template I have an if statement. Could it be the problem that the variables are not transferred? I wanted to have a snippet that I can use in multiple cases.

Probably, that still wouldn’t explain a 500 error. You should get a PHP error message for an undefined variable. Is debugging enabled?

But it helps if you always provide your code in context.

Provided that $image is defined, your code will work.

I got it working now for the cover image with the following code :slight_smile: :

<?php if ($image = $article->cover()->toFile()): ?>
                    ​<picture>
                        <source srcset="<?= $image->thumb(['width'   => 1000, 'quality' => 80, 'format' => 'avif'])->url() ?>" type="image/avif">
                        <source srcset="<?= $image->thumb(['width'   => 1000, 'quality' => 80, 'format' => 'webp'])->url() ?>" type="image/webp">
                        <source srcset="<?= $image->thumb(['width'   => 1000, 'quality' => 85, 'format' => 'jpg'])->url() ?>" type="image/jpeg">
                        <img src="<?= $image->url() ?>" alt="">
                    </picture>
                <?php else: ?>
                <?php if ($image = $article->image()): ?>
                <?php echo $image->thumb('blog')->html(); ?>
                <?php endif ?><?php endif ?>

Two questions left:

  1. How can I additionally provide multiple sizes as described here to load only the minimum required version?
  2. How can I make this work as a snippet? When I had exactly the same code in a snippet that I embedded after the first if statement I got the described error 500 (debugging turned on via ‘debug’ => true in the config.php but without effect).

The source tags srcset attribute also allows you to pass different sizes: <picture>: The Picture element - HTML: HyperText Markup Language | MDN

You would have to pass the $image variable to the snippet, see snippet docs: Snippets | Kirby CMS

This part can be simplifield with elseif


<?php elseif ($image = $article->image()): ?>
  <?php echo $image->thumb('blog')->html(); ?>
<?php endif ?>
1 Like

Thanks a lot for the really helpful support!
I saw that it should be possible to define multiple sizes in the srcset field of the picture tag but I thought I need to pass that information also to Kirby and the used thumb method doesn’t allow an array of multiple widths. If I do it like this it is always selecting the highest available width even if the available space for that image on my display is much smaller:

<source srcset="<?= $image->thumb(['width' => 500, 'quality' => 80, 'format' => 'avif'])->url() ?> 500w, <?= $image->thumb(['width' => 1000, 'quality' => 80, 'format' => 'avif'])->url() ?> 1000w" type="image/avif">

Hm, maybe srcset in the source tag allows only 1x, 2x values after all. If that is the case, you would have to provide a source tag for each size and each format

Like in this snippet: kirby3-webp/webp.php at master · HashandSalt/kirby3-webp · GitHub