So I have setup a macro based on the excellent article here;

{% macro responsive(asset, options={}) %}
{% import _self as self %}

{% set options = {
    alt: '',
    class: [],
    style: 'default'
}| merge(options) %}

    {% set transform = {
        mode: 'crop',
    } %}

{% set nativeWidth = asset.getWidth(false) %}

{% set config = {
    default: {
        srcsetWidths: [300, 600, 1000,],
        sizes: [
            '(max-width: 47.5em) 100vw',
        defaultWidth: 600

    cards: {
        srcsetWidths:   [345, 600, 700, 905, 1000, 1200, 1400],
        sizes: [
            '(max-width: 47.5em) 100vw',
            '(max-width: 60em) 50vw',
        defaultWidth: 600
} %}

{% set params = config[options.style] %}
{% set srcset = [asset.getUrl(false)~' '~nativeWidth~'w'] %}

{% for width in params['srcsetWidths'] %}
    {% if width < nativeWidth %}
    {% set srcset
         = srcset|merge([asset.getUrl(transform|merge({width: width}))~' '~width~'w'])
    {% endif %}
{% endfor %}

    {# src attr: transformed only if necessary #}
    {% if nativeWidth <= params['defaultWidth'] %}
      src="{{ asset.getUrl(false) }}"
    {% else %}
      src="{{ asset.getUrl(transform|merge({width: params['defaultWidth']})) }}"
    {% endif %}

    srcset="{{ srcset|join(', ') }}"
    sizes="{{ params['sizes']|join(', ') }}"

    {{ self._classAttr(options.class) }}
{% endmacro %}

However, I want to be able to generate each individual responsive set based on different transform parameters. The first instance I have is created a series of card images images for a 1x3 row of feature cards. These will be a fixed ratio which I want the system to handle and not the user. These cards have the following sizes for each srcset width;

  • 1400 x 875
  • 1200 x 750
  • 1000 x 625
  • 905 x 566
  • 700 x 438
  • 600 x 375
  • 345 x 216

I have created an image transform in the Control Panel called Card Image that has been set to crop and the width/height set to the largest size (1400x875). I wondered if I could use this handle in the macro, but I run into errors;

The merge filter only works with arrays or "Traversable", got "string" as first argument.

As I will have different use cases and create different 'responsive images' throughout the site, I want the flexibility of setting up different transforms, I thought it was perhaps sensible to keep these all in the control panel under the Image Transforms section, as these are easily referable and editable. Then pass in the required handle into the Macro.

Does anyone have a better approach or solution, and any ideas how I can overcome the error mentioned?


1 Answer 1


Merge operates on arrays or array-like things, and you probably handed it the string "card", which is why you got that error.

I think what you want to do here is use the transform in the control panel to define the aspect ratio, but use the img macro to determine which sizes to transform to.

You can calculate the aspect ratio like this:

{% set aspectRatio = asset.getHeight(options.style) / asset.getWidth(options.style) %}

And generate transforms like this:

transform|merge({width: width, height: width * aspectRatio})

You will want to be careful with the native (untransformed) image: only use it if it has the correct aspect ratio.

You will want to be careful with avoiding transforming to a larger image - skip the ones where the width would be greater than the native width and the ones where the height would be greater than the native height.

Using the crop transform instead of the stretch one (that the article uses) is the right thing to do too.

Also, consider the imager plugin, which has some useful srcset supporting features (and postdates that article)

  • I am going to take a look at imager as I believe this does what I want to achieve and more. It looks quite useful. Thanks for your help Marion. Commented Aug 9, 2016 at 17:52
  • 1
    +1 for Imager (and declaring all transforms inline, not via the CP). Commented Aug 9, 2016 at 17:58
  • I need to update the useful article, but I want to take this opportunity to advise against scaling an image to be just slightly smaller than its native size - it will get scaled twice - once by the server, and then probably again by the browser, and the image degrades with no compensating drop in image size Commented Aug 12, 2016 at 16:08

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.