Post with an image

A picturesque valley showcasing majestic mountains and lush forests, creating a serene and captivating landscape

image feature

Using the powerful Eleventy Image plugin, we have three ways to optimize images: HTML Transform, Markdown syntax, and Nunjucks shortcodes.

HTML Transform

Transforms any <img> or <picture> tags in HTML files as a post-processing step. Find the default settings directly in eleventy.config.js.

<img src="./co-located-image.jpg" alt="alt text">
<img src="/assets/images/absolute-path-image.jpg" alt="alt text">

We can pass in overrides for every instance and use attributes. By default all images are set to be lazy loaded, but we can override this by directly setting loading="eager" and decoding="sync"on the <img> element.

Another thing to note is the widths: ['auto'] setting, which by default only includes the original size image. We can set the dedicated widths to be used by adding eleventy:widths="800,1200" on the element. A single HTML width attribute (e.g. width="400") is also treated as an alias for eleventy:widths when it is a valid integer. If both are set on the same element, Image gives eleventy:widths priority. For images with Markdown syntax, I set fixed widths so we don’t need to set a value on every instance.

sizes defaults to auto, which is by default applied to all lazy loading images. See: https://github.com/whatwg/html/pull/8008. We can overwrite this with a normal sizes attribute, or, since Image v7, with eleventy:sizes, which also overrides any sizes set in the plugin config. Note:
The sizes attribute is required if widths has more than one entry. No default value for is added for sizes for eagerly loaded images, so we need to set it explicitly.

<img src="./co-located-image.jpg" alt="alt text" eleventy:widths="200,600" eleventy:sizes="100vw" loading="eager" decoding="sync">
A picturesque valley showcasing majestic mountains and lush forests, creating a serene and captivating landscape

If an image is already optimized elsewhere and you only want width/height (no Sharp re-encoding), Image v7 adds New passthrough format (usage: formats: [“passthrough”]).

<img src="./co-located-image.jpg" alt="alt text" eleventy:formats="passthrough">

Extra benefit: we can use both relative and absolute image sources.
One downside is that it comes with a higher build cost due to the post-processing step (unless you opt into passthrough).

More info: https://www.11ty.dev/docs/plugins/image/#html-transform

Markdown syntax

This also uses Image HTML Transform .
The markdown sytnax for images creates the <img> element the plugin is looking for, and then transforms it to the <picture> element (if more than one format is set).

In src/_config/plugins/markdown.js I customized the Markdown rendering for images slightly. What normally would become a title attribute is used to create the caption (<figcaption> within a <figure> element). Note that I set a fixed widths value instead of auto as the default.

![alt text](/path/to/image 'caption text')
![Close-up...](/assets/images/gallery/asturias-4.jpg) 'I used a portrait lens for this one'

Close-up with unfocused background of a vibrant large blue butterfly gracefully perched on a delicate flower amidst lush green gras
I used a portrait lens for this one

We can also add custom attributes here (Kudos to Aleksandr), to overwrite the default widths, have the image eagerly loaded, or add a class attribute, etc.

![alt text](/path/to/image){attrs}
![Close-up...](/assets/images/gallery/asturias-2.jpg){loading="eager" decoding="sync" eleventy:widths="400" eleventy:sizes="100vw" class="grayscale"}

Close-up of a delicate white flower with a yellow center, surrounded by green leaves

As the Markdown syntax is based on the HTML Transform, we must also add a custom sizes attribute to the image if we want to eager-load the image.

Nunjucks shortcodes

There are two Nunjucks shortcodes available: image and imageKeys. All skipped or left out parameters are set to their default values: an empty string if no alt text is passed, loading = 'lazy', the <picture> element gets its set of images from the default widths=[650,960,1400] and compares to a condition of sizes="auto" (for lazy loading images) or 100vw (for eager loading images), formats are ['avif', 'webp', 'jpeg'].

Positional parameters Shortcode

The positional parameters shortcode is the legacy approach and requires the arguments to be passed in the correct order.

The most basic version contains only the path to the image.

{% image "path to image" %}

We can pass in manually all the conditions, and add null to skip. The arguments include classes for the outer container ( <picture> or <figure> element), and for the <img> element.

{% image "path to image", "alt text", "caption text", "eager", "container class names", "img class names", [200, 400], "(min-width:30em) 50vw, 100vw", ['webp', 'jpeg'] %}
{% image "path to image", "alt text", null, "eager" %}
A traditional Asturian village with it's raised granaries, surrounded by lush green hills and mountains
An example for the positional parameters shortcode.

Example: predefine widths and sizes using Nunjuck’s set tag or front matter fields, and dynamically get the image path, like I do in the “Built with” template.

{% set widths = [400, 520] %}
{% set sizes = '(max-width: 615px) 50vw, 100vw' %}

{% image "/assets/images/screenshots/" + site.filename + ".jpg", site.name, null, "lazy", null, null, widths, sizes %}

Named Parameters Shortcode

Remembering the order of the arguments is a bit of a pain, so I added a second shortcode: imageKeys.

This shortcode allows us to specify parameters in any order or only include the ones we need to customize. We need to pass the parameters as a JSON object with the key-value pairs.

{% imageKeys {
  "src": "/assets/images/gallery/asturias-3.jpg",
  "alt": "A traditional Asturian village with it's raised granaries, surrounded by lush green hills and mountains",
  "caption": "An example for the named parameters shortcode.",
  "loading": "lazy",
  "containerClass": "text-center",
  "imageClass": "grayscale",
  "widths": [200, 400],
  "sizes": "(min-width:30em) 50vw, 100vw",
  "formats": ["webp", "jpeg"]
} %}
A traditional Asturian village with it's raised granaries, surrounded by lush green hills and mountains
An example for the named parameters shortcode.

Example: if we only need to customize alt text and sizes:

{% imageKeys {
  "sizes": '(min-width:30em) 50vw, 100vw',
  "alt": "A traditional Asturian village with it's raised granaries, surrounded by lush green hills and mountains",
  "src": "/assets/images/photo.jpg"
} %}

The shortcodes are defined in src/_config/shortcodes/image.js. They also set slot="image" on their container element, so they can be used with any WebC component that contains a <slot name="image"></slot>, see src/_includes/webc/custom-card.web for example.

Since we are using them alongside the Image HTML Transform method, the shortcodes add eleventy:ignore to the <img> attributes so the images aren’t processed twice.

Comparing Shortcode and HTML Transform

The shortcode can be much terser than the HTML syntax, while the HTML syntax is more readable and has a well known structure.

These two approaches produce (almost) the same output:

{% image image, alt or "", credit, "eager", "feature", "grayscale" %}

<figure class="feature">
  <img src="{{ image }}" alt="{{ alt or '' }}" loading="eager" decoding="sync" class="grayscale">
  {% if credit %}
    <figcaption>{{ credit }}</figcaption>
  {% endif %}
</figure>
A picturesque valley showcasing majestic mountains and lush forests, creating a serene and captivating landscape
Example image using the positional shortcode
A picturesque valley showcasing majestic mountains and lush forests, creating a serene and captivating landscape
Example image using the HTML syntax

Animated images

Animated GIF and WebP sources need sharpOptions: { animated: true } on Eleventy Image (currently set for both the HTML Transform plugin and the image shortcodes). When the source has multiple frames, Image v6+ keeps only animation-friendly output formats (typically WebP and/or GIF) from the formats list.

Built with Eleventy animated badge

(Badge by Chris Burnell. For crisp pixel art, use image-rendering: pixelated.)

More:


View this page on GitHub.