Thumb array rule doesn't work

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

The template I am using has a media query for @media (min-width: 768px) { .md\:w-2\/3 { width: 66.666667%; } } and this is the element I came up with:

​<picture>
  <source srcset="<?= $image->thumb(['width'   => 400, 'quality' => 80, 'format' => 'avif'])->url() ?> 400w, <?= $image->thumb(['width'   => 800, 'quality' => 80, 'format' => 'avif'])->url() ?> 800w, <?= $image->thumb(['width'   => 1200, 'quality' => 80, 'format' => 'avif'])->url() ?> 1200w, <?= $image->thumb(['width'   => 1600, 'quality' => 80, 'format' => 'avif'])->url() ?> 1600w" sizes="(max-width: 767px) calc(0.8 * 100vw), calc(0.61 * 100vw)" type="image/avif">
  <source srcset="<?= $image->thumb(['width'   => 400, 'quality' => 80, 'format' => 'webp'])->url() ?> 400w, <?= $image->thumb(['width'   => 800, 'quality' => 80, 'format' => 'webp'])->url() ?> 800w, <?= $image->thumb(['width'   => 1200, 'quality' => 80, 'format' => 'webp'])->url() ?> 1200w, <?= $image->thumb(['width'   => 1600, 'quality' => 80, 'format' => 'webp'])->url() ?> 1600w" sizes="(max-width: 767px) calc(0.8 * 100vw), calc(0.61 * 100vw)" type="image/webp">
  <img src="<?= $image->url() ?>" srcset="<?= $image->thumb(['width'   => 400, 'quality' => 80])->url() ?> 400w, <?= $image->thumb(['width'   => 800, 'quality' => 80])->url() ?> 800w, <?= $image->thumb(['width'   => 1200, 'quality' => 80])->url() ?> 1200w, <?= $image->thumb(['width'   => 1600, 'quality' => 80])->url() ?> 1600w" sizes="(max-width: 767px) calc(0.8 * 100vw), calc(0.61 * 100vw)" decoding="async" loading="lazy" alt="" style="background-size: cover; background-image: url('data:image/svg+xml;charset=utf-8,%3Csvg xmlns=\'http%3A//www.w3.org/2000/svg\' xmlns%3Axlink=\'http%3A//www.w3.org/1999/xlink\' viewBox=\'0 0 1280 853\'%3E%3Cfilter id=\'b\' color-interpolation-filters=\'sRGB\'%3E%3CfeGaussianBlur stdDeviation=\'.5\'%3E%3C/feGaussianBlur%3E%3CfeComponentTransfer%3E%3CfeFuncA type=\'discrete\' tableValues=\'1 1\'%3E%3C/feFuncA%3E%3C/feComponentTransfer%3E%3C/filter%3E%3Cimage filter=\'url(%23b)\' x=\'0\' y=\'0\' height=\'100%25\' width=\'100%25\' xlink%3Ahref=\'data%3Aimage/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAkAAAAGCAIAAACepSOSAAAACXBIWXMAAC4jAAAuIwF4pT92AAAAs0lEQVQI1wGoAFf/AImSoJSer5yjs52ktp2luJuluKOpuJefsoCNowB+kKaOm66grL+krsCnsMGrt8m1u8mzt8OVoLIAhJqzjZ2tnLLLnLHJp7fNmpyjqbPCqLrRjqO7AIeUn5ultaWtt56msaSnroZyY4mBgLq7wY6TmwCRfk2Pf1uzm2WulV+xmV6rmGyQfFm3nWSBcEIAfm46jX1FkH5Djn5AmodGo49MopBLlIRBfG8yj/dfjF5frTUAAAAASUVORK5CYII=\'%3E%3C/image%3E%3C/svg%3E'); ">
</picture>

The problem with this code is that always the highest width is provided even if I am emulating a small device screen/viewport with the browser developer tools. What am I missing?

What @texnixe wrote above…

In the mentioned documentation it sounds as if my approach should work:

The srcset attribute is used to offer list of possible images based on size .

It is composed of a comma-separated list of image descriptors. Each image descriptor is composed of a URL of the image, and either…

  • a width descriptor , followed by a w (such as 300w );
    OR
  • a pixel density descriptor , followed by an x (such as 2x ) to serve a high-res image for high-DPI screens.

Also this documentation lists this but I get confused by the many combination possibilities.
Is there maybe any plugin that I can just use that does the same? I just want to make sure that always the best possible image (format/size etc.) is delivered.

Yes, I saw that as well but couldn’t really get it to work.

I might be talking out of my hat, but I believe this is actually triggered by device width, not viewport width. To truly see it, you need to actually look on a small screen device. Not sure what server you are using but if its something with BroswerSync, it will give you an external URL you can pull up on a phone / tablet. From there you can remote debug the phones browser from Chrome or Safari on your desktop. Google can help you with how to do that.

So it works actually differently from image srcset?

I believe so, yes. I think its not working because with emulating mobiles in the browser, your device width is still the width of the computer monitor, triggering the highest res image. You need to use Apple simulator that comes with xcode, or the the simulator that comes with Android studio and remote debug to do a real test.

Or remote debug a real phone / tablet via browsersync.

With my mentioned code it seems to work somehow but the behaviour is really weird.
I get multiple kinds of image sizes generated by Kirby (at least based on the file name) but in the end they are all the same.
I found this out with a test from web.dev. One example URL:

https://domain.tld/kirbytest/media/pages/blog/vierter-beitrag/8a7534e6bb-1628195522/img-20170217-122206-480x-q48.avif

Based on the file name I would assume it is an AVIF image with 480px width and a quality level of 48 but instead it is the original jpeg in full quality and size:

Whats the order of the sources in your picture tag? Browsers read the first format they understand. You need to list out the Avif sources first (quite exoctic still) Webp next (reasonable support), and Jpeg last (supported everywhere).

It is in exactly that order: Thumb array rule doesn't work - #21 by Peleke

Hmmm tricky. With Kirby 3.6, the webp and avif files are file versions i think which end up in the media folder. With my webp plugin, i create webp files in the content folders as files in their own right.

For what its worth, i loop over an array of sizes and variants to get the picture tag Maybe you can adapt that.

That feature was improved by my good friend @nilshoerrmann maybe he can help here.

1 Like

I saw it and have not enough PHP knowledge to extend it to this use case.
Could the behavior also be a bug of the alpha 3?

Have you tested if your imagemagic version actually supports those formats? e.g. tested on the command line?

1 Like

Indeed that was the case. Otherwise the following code now seems to work correctly:

​<picture>
  <source srcset="<?= $image->thumb(['width'   => 400, 'quality' => 48, 'format' => 'avif'])->url() ?> 400w, <?= $image->thumb(['width'   => 800, 'quality' => 48, 'format' => 'avif'])->url() ?> 800w, <?= $image->thumb(['width'   => 1200, 'quality' => 48, 'format' => 'avif'])->url() ?> 1200w, <?= $image->thumb(['width'   => 1600, 'quality' => 48, 'format' => 'avif'])->url() ?> 1600w" sizes="(max-width: 767px) calc(0.8 * 100vw), calc(0.61 * 100vw)" type="image/avif">
  <source srcset="<?= $image->thumb(['width'   => 400, 'quality' => 55, 'format' => 'webp'])->url() ?> 400w, <?= $image->thumb(['width'   => 800, 'quality' => 55, 'format' => 'webp'])->url() ?> 800w, <?= $image->thumb(['width'   => 1200, 'quality' => 55, 'format' => 'webp'])->url() ?> 1200w, <?= $image->thumb(['width'   => 1600, 'quality' => 55, 'format' => 'webp'])->url() ?> 1600w" sizes="(max-width: 767px) calc(0.8 * 100vw), calc(0.61 * 100vw)" type="image/webp">
  <img src="<?= $image->url() ?>" height="<?= $image->height() ?>" width="<?= $image->width() ?>" srcset="<?= $image->thumb(['width'   => 400, 'quality' => 50])->url() ?> 400w, <?= $image->thumb(['width'   => 800, 'quality' => 50])->url() ?> 800w, <?= $image->thumb(['width'   => 1200, 'quality' => 50])->url() ?> 1200w, <?= $image->thumb(['width'   => 1600, 'quality' => 50])->url() ?> 1600w" sizes="(max-width: 767px) calc(0.8 * 100vw), calc(0.61 * 100vw)" decoding="async" loading="lazy" alt="<?=$image->alt()?>" style="background-size: cover; background-image: url('data:image/svg+xml;charset=utf-8,%3Csvg xmlns=\'http%3A//www.w3.org/2000/svg\' xmlns%3Axlink=\'http%3A//www.w3.org/1999/xlink\' viewBox=\'0 0 1280 853\'%3E%3Cfilter id=\'b\' color-interpolation-filters=\'sRGB\'%3E%3CfeGaussianBlur stdDeviation=\'.5\'%3E%3C/feGaussianBlur%3E%3CfeComponentTransfer%3E%3CfeFuncA type=\'discrete\' tableValues=\'1 1\'%3E%3C/feFuncA%3E%3C/feComponentTransfer%3E%3C/filter%3E%3Cimage filter=\'url(%23b)\' x=\'0\' y=\'0\' height=\'100%25\' width=\'100%25\' xlink%3Ahref=\'data%3Aimage/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAkAAAAGCAIAAACepSOSAAAACXBIWXMAAC4jAAAuIwF4pT92AAAAs0lEQVQI1wGoAFf/AImSoJSer5yjs52ktp2luJuluKOpuJefsoCNowB+kKaOm66grL+krsCnsMGrt8m1u8mzt8OVoLIAhJqzjZ2tnLLLnLHJp7fNmpyjqbPCqLrRjqO7AIeUn5ultaWtt56msaSnroZyY4mBgLq7wY6TmwCRfk2Pf1uzm2WulV+xmV6rmGyQfFm3nWSBcEIAfm46jX1FkH5Djn5AmodGo49MopBLlIRBfG8yj/dfjF5frTUAAAAASUVORK5CYII=\'%3E%3C/image%3E%3C/svg%3E'); ">
</picture>

I wish that this kind of feature will be integrated natively soon to save the hassle of creating it manually.
Is there any way to use this snippet for rendered articles as well (everything that is consumed from a content txt)?

What do you mean? Automatically integrating responsive images without knowing where these images are used and how doesn’t really make sense.