zfb
GitHub repository

Type to search...

to open search from anywhere

Image dimensions

Opt-in
Created Jun 24, 2026Takeshi Takatsudo

Auto-detect and inject width/height attributes on local img elements to eliminate Cumulative Layout Shift.

The imageDimensions feature reads image file headers at build time and injects width and height attributes on <img> elements that reference local files. Providing these attributes lets browsers allocate the correct space before the image loads, eliminating Cumulative Layout Shift (CLS).

Reference: rehype-img-size.

Enable

// zfb.config.ts
export default defineConfig({
  markdown: {
    features: {
      imageDimensions: {},
    },
  },
});

Behaviour

For each <img> element, the plugin:

  1. Skips elements that already carry width or height attributes.

  2. Skips data: URLs unconditionally. Skips http://, https://, and protocol-relative (//) URLs when skipRemote is true (the default).

  3. Resolves the src to an absolute path (see Source resolution below).

  4. For raster images, reads only the file header — no full decode occurs — and injects width="W" height="H".

  5. For SVG files (which carry no raster header), reads the intrinsic size from the markup: an explicit width/height pair (in user units or px) is used when present, otherwise the viewBox supplies the size/aspect ratio. An SVG with no determinable size is left unchanged, silently.

  6. If a raster file cannot be found or is not a recognised image format, emits a build warning and leaves the element unchanged. Undimensionable SVGs do not warn.

Supported formats: PNG, JPEG, GIF, WebP, AVIF (header probe) and SVG (parsed from width/height/viewBox).

Source resolution

The plugin resolves src values against the file system using BuildContext:

  • Absolute paths (e.g. /img/hero.png) are resolved against the project's public directory.

  • Relative paths (e.g. ./assets/hero.png, assets/hero.png) are resolved relative to the markdown source file's directory.

  • Remote and data: URLs are skipped silently.

Options

  • skipRemote (default true) — when true, http://, https://, and protocol-relative (//) image sources are skipped. Set to false only for unusual setups; probing remote images requires network access at build time. data: URLs are always skipped regardless of this setting.

imageDimensions: { skipRemote: false },

Example

Given a 400×300 PNG at public/images/hero.png and this markdown:

![Hero image](/images/hero.png)

The plugin produces:

<img src="/images/hero.png" alt="Hero image" width="400" height="300">

An <img> with explicit dimensions is left unchanged:

<img src="/images/hero.png" width="200" height="150" />

Caching

The plugin caches (path, mtime) → (width, height) in memory. A second <img> reference to the same file within the same build hits the cache rather than re-reading the file.

Ordering

ImageDimensionsPlugin runs in the hast phase, before SyntectPlugin. It injects width and height on <img> elements found in the document.

Requirements

This feature uses the wave-6 BuildContext seam. The pipeline must be invoked via Pipeline::run_with_context (or Pipeline::apply_hast_visitors_with_context) for dimensions to be injected. When the feature is wired but run (without context) is called, the plugin is a no-op.

Revision History

Takeshi TakatsudoCreated: 2026-06-25T05:17:25+09:00Updated: 2026-06-25T05:17:25+09:00

AI Assistant

Ask a question about the documentation.