<p>You can write a function, a utility template or a macro to make repetitive tasks like generating responsive images easier. I usually prefer templates, because they're easy to extend and they can take a lot of optional arguments without the user needing to pass all of them.</p>
<p>Building your own utility templates is a good time investments, since you can create a set of parameters / options into the template that you can use wherever you want to display images in your templates.</p>
<p>For example, here's a simple responsive image template that will take an image asset and a list of transforms and output an <code>&lt;img&gt;</code> tag:</p>
<pre class="lang-twig prettyprint-override"><code>{# utils/responsive-image.twig #}
{%- set transforms = transforms|default([]) -%}
{%- set transformedImages = transforms|map(transform =&gt; image.copyWithTransform(transform)) -%}
{%- set srcset = transformedImages|map(image =&gt; &quot;#{image.getUrl()} #{image.width}w&quot;) -%}
{%- set attributes = attributes ?? {} -%}

&lt;img {{ attr(attributes|merge({ srcset: srcset|join(', '), })) }}&gt;
</code></pre>
<p>Since this template accepts a list of <a href="https://docs.craftcms.com/api/v3/craft-elements-asset.html#public-methods" rel="nofollow noreferrer">transforms</a>, you can pass it any parameters that are accepted by <a href="https://docs.craftcms.com/api/v3/craft-elements-asset.html#public-methods" rel="nofollow noreferrer">Asset.getUrl()</a>. So both named transforms and hashes will work:</p>
<pre class="lang-twig prettyprint-override"><code>{% set image = entry.header_image.one() %}
{{ include('utils/responsive-image', {
    image: image,
    transforms: [{ width: 300, height: 300 }, { width: 600, height: 600 }],
}, with_context = false) }}
</code></pre>
<pre class="lang-twig prettyprint-override"><code>{% set image = entry.header_image.one() %}
{{ include('utils/responsive-image', {
    image: image,
    transforms: ['thumbnail', 'medium', 'mediumLarge'],
}, with_context = false) }}
</code></pre>
<p>Note the utility template also includes an optional parameter to specify additional attributes for the <code>&lt;img&gt;</code> tag. Here's a complete example:</p>
<pre class="lang-twig prettyprint-override"><code>{% set image = entry.header_image.one() %}
{{ include('utils/responsive-image', {
    image: image,
    transforms: [
        { width: 300, height: 300, mode: 'crop', position: 'top-center'},
        { width: 600, height: 600 }
    ],
    attributes: {
        width: 300,
        height: 300,
        srcset: '(min-width: 300px) 300px, 100vw',
        class: 'my-responsive-image',
    },
}, with_context = false) }}
</code></pre>
<p>Once you have the basic setup in place, you can expand your utility template to handle more repetitive tasks for you. For example, my utility template for responsive images can:</p>
<ul>
<li>Generate a <code>&lt;picture&gt;</code> with multiple sources.</li>
<li>Automatically generate alternative <code>&lt;source&gt;</code> tags with WebP images.</li>
<li>Apply a fixed aspect ratio to all transforms.</li>
<li>Handle SVGs gracefully.</li>
<li>Take the <code>alt</code> text from the asset's <code>alt</code> field, if it exists.</li>
<li>… and much more.</li>
</ul>

CC BY-SA 4.0
2021-09-27T09:50:53.973Z
Thanks for this, I'd be very interested to see the full version of your img template if you'd like to share it...
James Smith
CC BY-SA 4.0
2021-09-29T09:10:55.037Z
@JamesSmith Sorry, I developed that template for work, so I can't share it in full. But its a good exercise to develop your own starting with something small like my example here and then add features/parameters as they come up. It also really depends on how you build your templates and how you usually incorporate images, so what you end up with could focus on totally different aspects than my utility template!
MoritzLost
CC BY-SA 4.0
2022-06-16T01:42:33.987Z
This is really cool @MoritzLost - Can I ask, how would you place the mode? As im trying to crop with a specific focal point but am not clear on how to achieve this outcome
Wally
CC BY-SA 4.0
2022-06-16T18:03:15.387Z
@Wally If you use the `transforms` parameter as in the starter template above, you can just include `crop` and `mode` in the [transform definition](https://craftcms.com/docs/3.x/image-transforms.html#defining-transforms-in-your-templates). I've updated the usage example code to include those parameters. In the full version of the utility template I use for my projects, both of those can be passed as optional parameters as well and are automatically merged into the transforms if passed.
MoritzLost
CC BY-SA 4.0
2022-06-17T01:55:47.707Z
@MoritzLost amazing like always!
Wally
CC BY-SA 4.0
2023-07-11T20:17:43.047Z
@MoritzLost Any chance you could share your code with the picture element?
CreateSean
CC BY-SA 4.0
2023-07-12T13:19:19.513Z
@CreateSean I can't share the full template as it's part of commercial projects. But I would recommend building utility templates like those yourself anyway, this is the only way they're gonna make sense to you and fit your use-case. My utility template can output a `<picture>` element with multiple `<source>` elements – it does that by accepting a `sources` variable that holds an array of `transform` definitions as well as some additional parameters (`media`, `width`, `height`) etc.
MoritzLost
CC BY-SA 4.0
2021-09-24T09:40:58.253Z
2022-06-16T18:02:57.717Z
2022-06-16T18:02:57.717Z
MoritzLost
<p>Craft has a newer asset method called <a href="https://craftcms.com/docs/3.x/image-transforms.html#generating-srcset-sizes" rel="nofollow noreferrer">getSrcset</a> which should be close to what you need. Here's the code example from the docs:</p>
<pre><code>{% do asset.setTransform({ width: 300, height: 300 }) %}
{{ tag('img', {
  src: asset.url,
  width: asset.width,
  height: asset.height,
  srcset: asset.getSrcset(['1.5x', '2x', '3x']),
  alt: asset.title,
}) }}
</code></pre>
<p>You can also skip the transform and use explicit widths (rather than the 1x, 2x variants) like this:</p>
<pre><code>{{ tag('img', {
  src: asset.url,
  width: asset.width,
  height: asset.height,
  srcSet: asset.getSrcset(['414w', '768w', '1024w', '1600w', '1920w']),
  alt: asset.title,
}) }}
</code></pre>
<p>Assuming you already have transforms set for those sizes, it should use the same rendered images.</p>
<p>And if you wanted to skip the <code>src</code> tag for some reason, you could write it like this:</p>
<pre><code>&lt;img src=&quot;asset.url&quot;
  width=&quot;asset.width&quot;
  height=&quot;asset.height&quot;
  srcSet=&quot;asset.getSrcset(['414w', '768w', '1024w', '1600w', '1920w'])&quot;
  alt=&quot;asset.title&quot;
/&gt;
</code></pre>

CC BY-SA 4.0
2021-09-29T14:09:09.117Z
That's useful, and close to what I'm looking for.  The downside is if I change my 414 transform to say 480, then I have to find and replace all instances of it, rather than being able to reference it by name, i.e. `thumbnail`
MrCarrot
CC BY-SA 4.0
2021-09-29T19:06:45.260Z
Yeah we don’t use many named transforms so that typically hasn’t been a problem in our case. We just generate them on the fly whenever the template is rendered and then the transformed assets are cached for future use.
Dalton Rooney
CC BY-SA 4.0
2021-09-28T19:46:49.077Z
2021-09-28T19:46:49.077Z
Dalton Rooney
<p>I come from a WordPress background, so I'm attempting to create responsive images the way I'm accustomed to with WordPress.  Perhaps that's the wrong approach, I'm not sure.</p>
<p>In WordPress I would define five images size: <code>thumbnail</code>, <code>medium</code>, <code>medium_large</code>, <code>large</code>, <code>XL</code> and I would specify a width for each.  Typically I would define the widths as <code>414</code>, <code>768</code>, <code>1024</code>, <code>1600</code> and <code>1920</code> pixels respectively.  For the <code>sizes</code> attribute I would specify this manually on an image-by-image basis.</p>
<p>Outputting an image would look like this:</p>
<pre><code>&lt;img src=&quot;&lt;?php echo wp_get_attachment_image_url( $attachment_id, 'large' ); ?&gt;&quot;
     srcset=&quot;&lt;?php echo wp_get_attachment_image_srcset( $attachment_id ); ?&gt;&quot; /&gt;
</code></pre>
<p>The above would output all 5 image sizes to the <code>srcset</code> attribute.</p>
<p>So, back to Craft.  I have setup 5 asset transforms under <code>Settings</code> using the same handles as above.  I believe you can also set these up progmatically too.</p>
<p>I can then output each of my image sizes in the following way:</p>
<pre><code>{% set image = entry.aboutImage.withTransforms(['thumbnail', 'medium', 'mediumLarge', 'large', 'xl']).first() %}

&lt;img src=&quot;{{ image.getUrl('medium') }}&quot; alt=&quot;&quot;
     srcset=&quot;{{ image.getUrl('xl') }} {{ image.getWidth('xl') }}w,
             {{ image.getUrl('large') }} {{ image.getWidth('large') }}w,
             {{ image.getUrl('mediumLarge') }} {{ image.getWidth('mediumLarge') }}w,
             {{ image.getUrl('medium') }} {{ image.getWidth('medium') }}w,
             {{ image.getUrl('thumbnail') }} {{ image.getWidth('thumbnail') }}w&quot;
     width=&quot;{{ image.getWidth() }}&quot; height=&quot;{{ image.getHeight() }}&quot; /&gt;
</code></pre>
<p>Whilst this works okay, it's kind of cumbersome to repeat this for every image. Also, if the user uploads a very small image then I'm guessing it won't be available in all sizes.</p>
<p>I noticed that there is also this method:</p>
<pre><code>{{ asset.getImg({ width: 300, height: 300 }, ['1.5x', '2x', '3x']) }}
</code></pre>
<p>However I'd like to do the following, which doesn't work:</p>
<pre><code>{{ asset.getImg({ width: 300, height: 300 }, ['thumbnail', 'medium', 'mediumLarge', 'large', 'xl']) }}
</code></pre>
<p>I've read about <code>macros</code> but so far haven't really been able to fathom out how I'd achieve the above using a macro, or it it's necessary.</p>

<craft3><assets><image><responsive-images>
Generating srcset in a similar way to WordPress
# Generating srcset in a similar way to WordPress

(Asked by: username_0 on 2021-09-23)

I come from a WordPress background, so I'm attempting to create responsive images the way I'm accustomed to with WordPress.  Perhaps that's the wrong approach, I'm not sure.
In WordPress I would define five images size: thumbnail, medium, medium_large, large, XL and I would specify a width for each.  Typically I would define the widths as 414, 768, 1024, 1600 and 1920 pixels respectively.  For the sizes attribute I would specify this manually on an image-by-image basis.
Outputting an image would look like this:


The above would output all 5 image sizes to the srcset attribute.
So, back to Craft.  I have setup 5 asset transforms under Settings using the same handles as above.  I believe you can also set these up progmatically too.
I can then output each of my image sizes in the following way:
{% set image = entry.aboutImage.withTransforms(['thumbnail', 'medium', 'mediumLarge', 'large', 'xl']).first() %}



Whilst this works okay, it's kind of cumbersome to repeat this for every image. Also, if the user uploads a very small image then I'm guessing it won't be available in all sizes.
I noticed that there is also this method:
{{ asset.getImg({ width: 300, height: 300 }, ['1.5x', '2x', '3x']) }}

However I'd like to do the following, which doesn't work:
{{ asset.getImg({ width: 300, height: 300 }, ['thumbnail', 'medium', 'mediumLarge', 'large', 'xl']) }}

I've read about macros but so far haven't really been able to fathom out how I'd achieve the above using a macro, or it it's necessary.

**Tags:** craft3, assets, image, responsive-images


---

## 2 answers

### Answer by username_1 on 2021-09-24. Score: 3

You can write a function, a utility template or a macro to make repetitive tasks like generating responsive images easier. I usually prefer templates, because they're easy to extend and they can take a lot of optional arguments without the user needing to pass all of them.
Building your own utility templates is a good time investments, since you can create a set of parameters / options into the template that you can use wherever you want to display images in your templates.
For example, here's a simple responsive image template that will take an image asset and a list of transforms and output an  tag:
{# utils/responsive-image.twig #}
{%- set transforms = transforms|default([]) -%}
{%- set transformedImages = transforms|map(transform => image.copyWithTransform(transform)) -%}
{%- set srcset = transformedImages|map(image => "#{image.getUrl()} #{image.width}w") -%}
{%- set attributes = attributes ?? {} -%}



Since this template accepts a list of transforms, you can pass it any parameters that are accepted by Asset.getUrl(). So both named transforms and hashes will work:
{% set image = entry.header_image.one() %}
{{ include('utils/responsive-image', {
    image: image,
    transforms: [{ width: 300, height: 300 }, { width: 600, height: 600 }],
}, with_context = false) }}

{% set image = entry.header_image.one() %}
{{ include('utils/responsive-image', {
    image: image,
    transforms: ['thumbnail', 'medium', 'mediumLarge'],
}, with_context = false) }}

Note the utility template also includes an optional parameter to specify additional attributes for the  tag. Here's a complete example:
{% set image = entry.header_image.one() %}
{{ include('utils/responsive-image', {
    image: image,
    transforms: [
        { width: 300, height: 300, mode: 'crop', position: 'top-center'},
        { width: 600, height: 600 }
    ],
    attributes: {
        width: 300,
        height: 300,
        srcset: '(min-width: 300px) 300px, 100vw',
        class: 'my-responsive-image',
    },
}, with_context = false) }}

Once you have the basic setup in place, you can expand your utility template to handle more repetitive tasks for you. For example, my utility template for responsive images can:

Generate a  with multiple sources.
Automatically generate alternative  tags with WebP images.
Apply a fixed aspect ratio to all transforms.
Handle SVGs gracefully.
Take the alt text from the asset's alt field, if it exists.
… and much more.

> **Comments:**
> **username_2**: Thanks for this, I'd be very interested to see the full version of your img template if you'd like to share it...  
> **username_1**: @JamesSmith Sorry, I developed that template for work, so I can't share it in full. But its a good exercise to develop your own starting with something small like my example here and then add features/parameters as they come up. It also really depends on how you build your templates and how you usually incorporate images, so what you end up with could focus on totally different aspects than my utility template!  
> **username_3**: This is really cool @username_1 - Can I ask, how would you place the mode? As im trying to crop with a specific focal point but am not clear on how to achieve this outcome  
> **username_1**: @username_3 If you use the `transforms` parameter as in the starter template above, you can just include `crop` and `mode` in the [transform definition](https://craftcms.com/docs/3.x/image-transforms.html#defining-transforms-in-your-templates). I've updated the usage example code to include those parameters. In the full version of the utility template I use for my projects, both of those can be passed as optional parameters as well and are automatically merged into the transforms if passed.  
> **username_3**: @username_1 amazing like always!  
> **username_4**: @username_1 Any chance you could share your code with the picture element?  
> **username_1**: @username_4 I can't share the full template as it's part of commercial projects. But I would recommend building utility templates like those yourself anyway, this is the only way they're gonna make sense to you and fit your use-case. My utility template can output a `<picture>` element with multiple `<source>` elements – it does that by accepting a `sources` variable that holds an array of `transform` definitions as well as some additional parameters (`media`, `width`, `height`) etc.  

---

### Answer by username_5 on 2021-09-28. Score: 1

Craft has a newer asset method called getSrcset which should be close to what you need. Here's the code example from the docs:
{% do asset.setTransform({ width: 300, height: 300 }) %}
{{ tag('img', {
  src: asset.url,
  width: asset.width,
  height: asset.height,
  srcset: asset.getSrcset(['1.5x', '2x', '3x']),
  alt: asset.title,
}) }}

You can also skip the transform and use explicit widths (rather than the 1x, 2x variants) like this:
{{ tag('img', {
  src: asset.url,
  width: asset.width,
  height: asset.height,
  srcSet: asset.getSrcset(['414w', '768w', '1024w', '1600w', '1920w']),
  alt: asset.title,
}) }}

Assuming you already have transforms set for those sizes, it should use the same rendered images.
And if you wanted to skip the src tag for some reason, you could write it like this:

> **Comments:**
> **username_0**: That's useful, and close to what I'm looking for.  The downside is if I change my 414 transform to say 480, then I have to find and replace all instances of it, rather than being able to reference it by name, i.e. `thumbnail`  
> **username_5**: Yeah we don’t use many named transforms so that typically hasn’t been a problem in our case. We just generate them on the fly whenever the template is rendered and then the transformed assets are cached for future use.  

---

