Skip to content
Foundations

Content images

Pictures are the heaviest thing a page ships and the easiest thing to get subtly wrong. Five decisions cover it.

Optimise the file, not the request

GdImage reserves the box, draws the brand's survey grid underneath, and sets loading and decoding the way content wants them. It renders a plain img.

There is no resizing service, and that is deliberate. Ship each file at the size it will actually be displayed, in a modern format — a cover shown at 800px is a 1600px WebP, and nothing needs to derive anything at request time. For a system whose pictures are its own drawn artwork, one well-chosen file is smaller than the machinery that would produce five.

A site with a real photo library should still run a pipeline. srcset and sizes pass straight through, so its output lands here without changing any markup.

Where the file goes

Nuxt gives two directories and they are not interchangeable. Pick by asking one question: does a bundler know this path at build time?

The path comes from CONTENT

public/images/…

An article record, a CMS field, an API response. Served untouched at the URL you chose — which is what a path a bundler cannot follow needs.

The path is written in CODE

app/assets/images/…

A component always draws this exact file. Vite rewrites it to a content-hashed URL, so it can be cached forever and changes bust the cache on their own.

Alt text and captions are different jobs

alt is required on GdImage. Not as strictness for its own sake: an image without it is announced by its filename, and there is no way to tell a decorative image from a forgotten one unless somebody types the difference. Decorative? Pass alt="" — an empty string is an assertion.

An axonometric parcel with a dashed setback line and the block of buildable space standing inside it.
The dashed line is the rule; the solid is what the rule leaves.Riverton City scheme, illustrative
  • alt replaces the image. Read only when the picture cannot be seen. It should leave that reader knowing what a sighted reader knows.
  • caption accompanies it. Read by everyone, including the person looking straight at it — so it adds what the picture cannot say for itself.
  • credit is metadata. Attribution and licence, set quieter, and the field an audit greps for.

Putting the caption in alt makes a screen-reader user hear one sentence twice and never learn what the image showed. Leaving alt empty because the caption explains it makes the image disappear for them entirely.

Pick one shape per collection

ratio reserves the box before a byte arrives, so text below never jumps when the image lands. That is most of Cumulative Layout Shift on a content page, and it is one prop.

The second reason is alignment. A row of cards whose images disagree about shape will never line up, and no grid CSS fixes it — the disagreement is inside the card. Choose one ratio for a collection and crop to it.

21/9

16/9

3/2

4/3

1/1

4/5

Exactly one image is priority

Everything is lazy by default. The one image above the fold — usually an article's hero, usually the Largest Contentful Paint element — takes priority, which loads it eagerly at high fetch priority and preloads it.

Marking several defeats the purpose. Priority is an ordering, and an ordering in which everything comes first is not one: the browser opens every connection at once and arrives later at the image that mattered.

When there is no photograph

The system ships no photography, and a drawn panel is often the more honest answer anyway. GdCardMedia is the media zone for that case: the survey grid, a tint, and one glyph on a plaque.

GdImage falls back to the same texture. Before the image paints it is the ground; if the image never arrives it stays, and the picture glyph appears on the plaque. A reader sees a picture that is missing rather than a page that is broken.

GdCardMedia — chosen, not a failure

A cover that cannot be loaded

GdImage — the same texture, holding the shape

Navigate

Esc