Placeholder images #
Sometimes website layout depends on images that have specific dimensions. If these images are missing or have wrong sizes - layout just looks wrong or even breaks. In such situations, it's pretty useful to have a placeholder image that takes place of missing images and has the same dimensions as the missing image.
SVG placeholder macro #
This macro will output transformed image, and if the image is missing it will output placeholder image. Placeholder will have the same width and height that image was supposed to have - assuming that width and height were set in transform settings. If only width or only height was set, placeholder will take the form of the square. And if width and height are missing - placeholder will not be outputted.
The generated placeholder image is not file that exists on the server - it is SVG with specific dimensions (and SVG is just a string) that is encoded to URL format and put into src
of <img>
tag. Such a placeholder image is transparent - so we may give it some background-image
- for example, graphic like THIS. Or we can just give it some background color.
Here's macro code:
{%- macro transformOrPlaceholder(image, settings, attributes = {}) -%}
{# settings #}
{% set placeholderStyle = {
'background-image': 'url(placeholder.jpg)',
'background-position': 'center',
'background-size': 'cover',
} %}
{# logic #}
{% if image is not null %}
{% set src = image.getUrl(settings) %}
{% set attributes = attributes|merge({src: src}) %}
{{tag('img', attributes)}}
{% elseif settings.width is defined or settings.height is defined %}
{% set width = settings.width ?? settings.height %}
{% set height = settings.height ?? settings.width %}
{% set svg = '<svg xmlns="http://www.w3.org/2000/svg" width="'~width~'" height="'~height~'"/>'|url_encode %}
{% set src = 'data:image/svg+xml;charset=utf-8,'~svg %}
{% set attributes = attributes|merge({src: src}) %}
{% set attributes = attributes|merge({style: placeholderStyle}) %}
{{tag('img', attributes)}}
{% endif %}
{%- endmacro -%}
Macro has three parameters:
image
- asset object. Don't pass element query to macro, pass specific image object. So instead ofentry.someAssetField
, useentry.someAssetField.one()
.settings
image transform settings. Need to containwidth
and/orheight
for placeholder to appear. Rest of settings will be ignored while generating placeholder.attributes
- HTML attributes that will be assigned to<img>
element, like class. You can learn more about generating HTML attributes from Twig variables in THIS atricle.
Here's example use of macro:
{% import 'file_with_macro' as m %}
{% set ourImage = entry.someAssetField.one() %}
{% set transformSettings = {
width: 300,
height: 400,
format: 'jpg',
quality: 95,
} %}
{{m.transformOrPlaceholder(ourImage, transformSettings, {
class: 'some-class',
}) }}
You can also create a macro that just outputs placeholder image, without generating image transform:
{%- macro placeholder(settings, attributes = {}) -%}
{# settings #}
{% set placeholderStyle = {
'background-image': 'url(placeholder.jpg);',
'background-position': 'center;',
'background-size': 'cover;',
} %}
{# logic #}
{% if settings.width is defined or settings.height is defined %}
{% set width = settings.width ?? settings.height %}
{% set height = settings.height ?? settings.width %}
{% set svg = '<svg xmlns="http://www.w3.org/2000/svg" width="'~width~'" height="'~height~'"/>'|url_encode %}
{% set src = 'data:image/svg+xml;charset=utf-8,'~svg %}
{% set attributes = attributes|merge({src: src}) %}
{% set attributes = attributes|merge({style: placeholderStyle}) %}
{{tag('img', attributes)}}
{% endif %}
{%- endmacro -%}
And if you use Imager X (or old Imager), you can generate placeholder image using placeholder function.
Placeholder macro using external service #
There are many services that provide nicely formatted placeholder images. To obtain such an image, usually you just need to append width and height to URL of placeholder service.
For example - using placehold.co, you can get image with width 600px and height 400px under this address: https://placehold.co/600x400. Images generated by that website have the size of placeholder placed in the middle, in "width x height" format. By tinkering with address, you can also adjust things like font or text and background color.
Neat, right? Just keep in mind that by using external service, you are tying your website to it - and one day such service might just stop working. Or start acting up and generate images really slowly.
Let's use placehold.co service in macro - it will be used in the same way as SVG macro.
{%- macro transformOrPlaceholder(image, settings, attributes = {}) -%}
{% if image is not null %}
{% set src = image.getUrl(settings) %}
{% set attributes = attributes|merge({src: src}) %}
{{tag('img', attributes)}}
{% elseif settings.width is defined or settings.height is defined %}
{% set width = settings.width ?? settings.height %}
{% set height = settings.height ?? settings.width %}
{% set src = 'https://placehold.co/'~width~'x'~height %}
{% set attributes = attributes|merge({src: src}) %}
{{tag('img', attributes)}}
{% endif %}
{%- endmacro -%}
Do you like kittens? With placekitten.com service, you can have placeholder image featuring photo of kitten:
{%- macro transformOrPlaceholder(image, settings, attributes = {}) -%}
{% if image is not null %}
{% set src = image.getUrl(settings) %}
{% set attributes = attributes|merge({src: src}) %}
{{tag('img', attributes)}}
{% elseif settings.width is defined or settings.height is defined %}
{% set width = settings.width ?? settings.height %}
{% set height = settings.height ?? settings.width %}
{% set src = 'http://placekitten.com/'~width~'/'~height %}
{% set attributes = attributes|merge({src: src}) %}
{{tag('img', attributes)}}
{% endif %}
{%- endmacro -%}