imagery
Pictures in the Interface
The default is no photograph. Product UI earns its texture from type, spacing, and material, and every picture you add is an aspect ratio to lock, a placeholder to design, two themes to survive, and bytes on the critical path. A picture belongs only when the picture is the content: something a user uploaded, a product being sold, a chart of their data, or a screenshot of the thing you actually built. Benji Taylor's site is the reference case — 53 device frames showing real product work, and zero stock photographs, no 3D render, no hero image, not even a photo of himself. When a picture does belong, it ships with its ratio locked before a single byte arrives.
The sibling to keep straight is iconography. An icon is a glyph drawn to a stroke grid and sized against the type it sits beside; a picture is a raster or a scene with its own intrinsic ratio and load cost. If the asset has a stroke weight, it is iconography. Two more edges: how long an image may take before its placeholder becomes a loading state is ui-states, and the dimming ratio a photograph takes in the dark theme is dark-mode.
Work inside whatever image pipeline already exists. Look for next/image, Astro's <Image>, @nuxt/image, an image CDN (Cloudinary, imgix, Vercel's optimizer), or a plain <img> convention. Hand-writing srcset beside a framework component that generates it produces two competing sources of truth and one of them will rot. If the project has no pipeline, say so explicitly before adding one — that is a dependency decision, not an image decision.
Quick Reference
| You need | Open |
|---|---|
Format choice, srcset and sizes, lazy versus priority, SVG hygiene, the placeholder ladder |
references/formats-and-loading.md — open it before writing any <img> or <picture> markup. |
| Sizes, shapes, fallback chain, stacked groups, presence dots | references/avatars.md — open it the moment a person, team, or account is represented by a picture. |
Core Principles
- Lock the ratio before the bytes arrive. Set
aspect-ratioon the box andwidth/heightattributes on the<img>, even when CSS resizes it — the attributes are what let the browser reserve the space during parse. An image without reserved space is a layout shift with a delay fuse. The exception is genuinely unknown intrinsic dimensions at render time, which get a fixed-height container plusobject-fit: cover.