feat: add imageKeys shortcode
This commit is contained in:
parent
6c504570e1
commit
3ac344a129
5 changed files with 154 additions and 50 deletions
|
|
@ -89,6 +89,7 @@ export default async function (eleventyConfig) {
|
|||
// --------------------- Shortcodes
|
||||
eleventyConfig.addShortcode('svg', shortcodes.svgShortcode);
|
||||
eleventyConfig.addShortcode('image', shortcodes.imageShortcode);
|
||||
eleventyConfig.addShortcode('imageKeys', shortcodes.imageKeysShortcode);
|
||||
eleventyConfig.addShortcode('year', () => `${new Date().getFullYear()}`);
|
||||
|
||||
// --------------------- Events: after build
|
||||
|
|
|
|||
|
|
@ -14,7 +14,7 @@
|
|||
"favicons": "node ./src/_config/setup/generate-favicons.js",
|
||||
"colors": "node ./src/_config/setup/create-colors.js",
|
||||
"screenshots": "node ./src/_config/setup/generate-screenshots.js",
|
||||
"dev:11ty": "cross-env ELEVENTY_ENV=development eleventy --serve --quiet",
|
||||
"dev:11ty": "cross-env ELEVENTY_ENV=development eleventy --serve",
|
||||
"build:11ty": "cross-env ELEVENTY_ENV=production eleventy",
|
||||
"start": "npm run dev:11ty",
|
||||
"build": "npm run clean && npm run build:11ty"
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
import {imageShortcode} from './shortcodes/image.js';
|
||||
import {imageShortcode, imageKeysShortcode} from './shortcodes/image.js';
|
||||
import {svgShortcode} from './shortcodes/svg.js';
|
||||
|
||||
export default {imageShortcode, svgShortcode};
|
||||
export default {imageShortcode, imageKeysShortcode, svgShortcode};
|
||||
|
|
|
|||
|
|
@ -10,7 +10,13 @@ const stringifyAttributes = attributeMap => {
|
|||
.join(' ');
|
||||
};
|
||||
|
||||
export const imageShortcode = async (
|
||||
const errorSrcRequired = shortcodeName => {
|
||||
throw new Error(`src parameter is required for {% ${shortcodeName} %} shortcode`);
|
||||
};
|
||||
|
||||
// Handles image processing
|
||||
const processImage = async options => {
|
||||
let {
|
||||
src,
|
||||
alt = '',
|
||||
caption = '',
|
||||
|
|
@ -20,7 +26,8 @@ export const imageShortcode = async (
|
|||
widths = [650, 960, 1400],
|
||||
sizes = 'auto',
|
||||
formats = ['avif', 'webp', 'jpeg']
|
||||
) => {
|
||||
} = options;
|
||||
|
||||
// Prepend "./src" if not present
|
||||
if (!src.startsWith('./src')) {
|
||||
src = `./src${src}`;
|
||||
|
|
@ -65,3 +72,39 @@ export const imageShortcode = async (
|
|||
? `<figure slot="image"${containerClass ? ` class="${containerClass}"` : ''}>${pictureElement}<figcaption>${caption}</figcaption></figure>`
|
||||
: `<picture slot="image"${containerClass ? ` class="${containerClass}"` : ''}>${imageSources}<img ${imageAttributes}></picture>`;
|
||||
};
|
||||
|
||||
// Positional parameters (legacy)
|
||||
export const imageShortcode = async (
|
||||
src,
|
||||
alt,
|
||||
caption,
|
||||
loading,
|
||||
containerClass,
|
||||
imageClass,
|
||||
widths,
|
||||
sizes,
|
||||
formats
|
||||
) => {
|
||||
if (!src) {
|
||||
errorSrcRequired('image');
|
||||
}
|
||||
return processImage({
|
||||
src,
|
||||
alt,
|
||||
caption,
|
||||
loading,
|
||||
containerClass,
|
||||
imageClass,
|
||||
widths,
|
||||
sizes,
|
||||
formats
|
||||
});
|
||||
};
|
||||
|
||||
// Named parameters
|
||||
export const imageKeysShortcode = async (options = {}) => {
|
||||
if (!options.src) {
|
||||
errorSrcRequired('imageKeys');
|
||||
}
|
||||
return processImage(options);
|
||||
};
|
||||
|
|
|
|||
|
|
@ -1,15 +1,13 @@
|
|||
---
|
||||
title: 'Post with an image'
|
||||
description: "You can use Markdown, a Nunjucks shortcode or pure HTML to add images to your posts and pages."
|
||||
description: "We can use Markdown, Nunjucks shortcodes or pure HTML to add images to posts and pages."
|
||||
date: 2025-01-09
|
||||
tags: ['image', 'feature']
|
||||
image: '/assets/images/gallery/asturias-1.jpg'
|
||||
alt: 'A picturesque valley showcasing majestic mountains and lush forests, creating a serene and captivating landscape'
|
||||
credit: A photo I took.
|
||||
---
|
||||
|
||||
Using the powerful Eleventy Image plugin, we have three ways to optimize images: HTML Transform, Markdown syntax, and a Nunjucks shortcode.
|
||||
Using the powerful [Eleventy Image plugin](https://www.11ty.dev/docs/plugins/image/), we have three ways to optimize images: <a href="#html-transform">HTML Transform</a>, <a href="#markdown-syntax">Markdown syntax</a>, and <a href="#nunjucks-shortcodes">Nunjucks shortcodes</a>.
|
||||
|
||||
<a name="html-transform"></a>
|
||||
## 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`.
|
||||
|
|
@ -21,7 +19,7 @@ Transforms any `<img>` or `<picture>` tags in HTML files as a post-processing st
|
|||
|
||||
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. You can set the dedicated `widths` to be used by adding `eleventy:widths="800,1200"` on the element. For images with [Markdown syntax](/blog/post-with-an-image/#markdown-syntax), I set fixed `widths` so we don't need to set a value on every instance.
|
||||
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. For images with [Markdown syntax](/blog/post-with-an-image/#markdown-syntax), I set fixed `widths` so we don't need to set a value on every instance.
|
||||
|
||||
`sizes` defaults to `auto`, which is applied to all lazy loading images. For eager-loading images, the value is equivalent to `100vw` See: https://github.com/whatwg/html/pull/8008. We can _still_ overwrite this, by setting the `sizes` attribute directly on the `<img>` element, with something specific like `sizes="(max-width: 615px) 50vw, 100vw"`.
|
||||
|
||||
|
|
@ -31,8 +29,8 @@ Another thing to note is the `widths: ['auto']` setting, which by default only
|
|||
|
||||
<img src="./asturias-1.jpg" alt="A picturesque valley showcasing majestic mountains and lush forests, creating a serene and captivating landscape" eleventy:widths="200,600" sizes="(max-width: 615px) 50vw, 100vw" loading="eager" decoding="sync">
|
||||
|
||||
This makes this syntax equally powerfull as the [shortcode](/blog/post-with-an-image/#nunjucks-shortcode), and easier to read - with the extra benefit that we can use both relative and absolute image sources.
|
||||
Only "downside" ist, that it comes with a higher build cost due to the post-processing step.
|
||||
**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.
|
||||
|
||||
More info: https://www.11ty.dev/docs/plugins/image/#html-transform
|
||||
|
||||
|
|
@ -41,67 +39,125 @@ More info: https://www.11ty.dev/docs/plugins/image/#html-transform
|
|||
This also uses [Image HTML Transform ](https://www.11ty.dev/docs/plugins/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 a caption. Note that I set a fixed `widths` value instead of `auto` as the default.
|
||||
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.
|
||||
|
||||
```markdown
|
||||

|
||||
 'I used a portrait lens for this one'
|
||||
 'I used a portrait lens for this one'
|
||||
```
|
||||
|
||||

|
||||
|
||||
You can also add custom attributes here ([Kudos to Aleksandr](https://www.aleksandrhovhannisyan.com/blog/eleventy-image-transform/)), to overwrite the default `widths`, have the image eagerly loaded, or add a class etc.
|
||||
We can also add custom attributes here ([Kudos to Aleksandr](https://www.aleksandrhovhannisyan.com/blog/eleventy-image-transform/)), to overwrite the default `widths`, have the image eagerly loaded, or add a `class` attribute, etc.
|
||||
|
||||
```markdown
|
||||
{attrs}
|
||||
{loading="eager" decoding="sync" eleventy:widths="400" class="grayscale"}
|
||||
{loading="eager" decoding="sync" eleventy:widths="400" class="grayscale"}
|
||||
```
|
||||
|
||||
{loading="eager" decoding="sync" eleventy:widths="400" class="grayscale"}
|
||||
|
||||
## Nunjucks shortcode
|
||||
## Nunjucks shortcodes
|
||||
|
||||
The most basic version contains the path to the image (absolute) and alt text (can be an empty string if the image is decorative).
|
||||
### 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.
|
||||
|
||||
{% raw %}
|
||||
|
||||
```jinja2
|
||||
{% image "path to image", "alt text" %}
|
||||
{% image "path to image" %}
|
||||
```
|
||||
|
||||
{% endraw %}
|
||||
|
||||
It defaults to `loading = 'lazy'`, the picture element gets its set of images from `widths=[650,960,1400]` and compares to a condition of `sizes="auto"`.
|
||||
You can pass in manually all the conditions, add `null` to skip. The arguments include classes for the outer container ( `<picture>` or `<figure>` element), and for the `<img>` element.
|
||||
All skipped 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"`, formats are `['avif', 'webp', 'jpeg']`.
|
||||
|
||||
The shortcode is stored in `src/_config/shortcodes/image.js`.
|
||||
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.
|
||||
|
||||
{% raw %}
|
||||
|
||||
```jinja2
|
||||
{% image "path to image", "alt text", "caption text", "eager", "container class names", "img class names", [200, 400], "(min-width:30em) 50vw, 100vw" %}
|
||||
{% 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" %}
|
||||
```
|
||||
|
||||
{% endraw %}
|
||||
|
||||
{% image "/assets/images/gallery/asturias-3.jpg", "A traditional Asturian village with it's raised granaries, surrounded by lush green hills and mountains", "What a nice old house in black and white", "lazy", "text-center", "grayscale", [200, 400], "(min-width:30em) 50vw, 100vw" %}
|
||||
{% image "/assets/images/gallery/asturias-3.jpg", "A traditional Asturian village with it's raised granaries, surrounded by lush green hills and mountains", "An example for the positional parameters shortcode.", "lazy", "text-center", "grayscale", [200, 400], "(min-width:30em) 50vw, 100vw", ['webp', 'jpeg'] %}
|
||||
|
||||
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.
|
||||
**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](/blog/built-with/)" template.
|
||||
|
||||
{% raw %}
|
||||
|
||||
```jinja2
|
||||
{% 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 %}
|
||||
```
|
||||
|
||||
{% endraw %}
|
||||
|
||||
### 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.
|
||||
|
||||
{% raw %}
|
||||
|
||||
```jinja2
|
||||
{% 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"]
|
||||
} %}
|
||||
```
|
||||
|
||||
{% endraw %}
|
||||
|
||||
{% 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"]
|
||||
} %}
|
||||
|
||||
**Example:** if we only need to customize `alt` text and `sizes`:
|
||||
|
||||
{% raw %}
|
||||
|
||||
```jinja2
|
||||
{% 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"
|
||||
} %}
|
||||
```
|
||||
|
||||
{% endraw %}
|
||||
|
||||
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 <a href="#html-transform">Image HTML Transform</a> 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. It also includes the `slot="image"` attribute for seamless WebC component integration. However, it's less readable, and you must carefully order all arguments. On the other hand, the HTML syntax is much more readable and easier to maintain.
|
||||
|
||||
As for the higher build cost of post-processing, the shortcode images are being skipped using the `eleventy:ignore` attribute, but still seem to be processed somehow. I have yet to figure out if this is avoidable. If you set the `eleventy:ignore` on an HTML image though, it _is_ completely skipped and excluded from the processed images.
|
||||
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:**
|
||||
|
||||
|
|
@ -116,27 +172,31 @@ As for the higher build cost of post-processing, the shortcode images are being
|
|||
<figcaption>{{ credit }}</figcaption>
|
||||
{% endif %}
|
||||
</figure>
|
||||
|
||||
```
|
||||
|
||||
{% endraw %}
|
||||
|
||||
{% image image, alt or "", credit, "eager", "feature", "grayscale" %}
|
||||
{% set image = '/assets/images/gallery/asturias-1.jpg' %}
|
||||
{% set alt = 'A picturesque valley showcasing majestic mountains and lush forests, creating a serene and captivating landscape' %}
|
||||
|
||||
{% set credits = ['Example image using the positional shortcode', 'Example image using the HTML syntax'] %}
|
||||
|
||||
{% for credit in credits %}
|
||||
{% if loop.index == 1 %}
|
||||
{% image image, alt or "", credit, "eager", "feature", "grayscale" %}
|
||||
{% else %}
|
||||
<figure class="feature">
|
||||
<img src="{{ image }}" alt="{{ alt or '' }}" loading="eager" decoding="sync" class="grayscale">
|
||||
{% if credit %}
|
||||
<figcaption>{{ credit }}</figcaption>
|
||||
{% endif %}
|
||||
</figure>
|
||||
{% endif %}
|
||||
|
||||
{% endfor %}
|
||||
|
||||
More:
|
||||
- https://www.11ty.dev/docs/plugins/image/
|
||||
- https://www.youtube.com/watch?v=e0OHgC677ec
|
||||
- https://www.aleksandrhovhannisyan.com/blog/eleventy-image-transform/
|
||||
- https://coryd.dev/posts/2024/setting-up-image-transforms-in-eleventy
|
||||
|
||||
{%- css "local" -%}
|
||||
{%- include 'css/table.css' -%}
|
||||
{%- endcss -%}
|
||||
|
|
|
|||
Loading…
Reference in a new issue