responsive-image-contracts

Installation
SKILL.md

Responsive image contracts

A responsive image is a contract between the file you ship and the box it renders into. Linters can check that the syntax is valid; they cannot tell you the sizes value matches the real layout, that the intrinsic-width labels are honest, or that the LCP image loads first. This lens reviews that judgment: role-based sizing (hero vs grid cell vs thumbnail), load priority, and which candidate the browser actually downloads.

Checklist (lead with the trap)

  1. w-descriptor srcset with no sizes -> the browser assumes 100vw and downloads the widest candidate that fits the full viewport. A 400px thumbnail with srcset="...1600w" and no sizes fetches the 1600w file on a wide screen: wasted bytes and, if it is the LCP element, a slower paint. Add sizes describing the real rendered width.
  2. sizes must match the actual CSS layout, not a guess. sizes="100vw" on an image that renders in a 3-column grid (really ~33vw) over-downloads ~3x; a too-small sizes under-downloads and renders soft. sizes is a media-condition list read left-to-right, first true wins, with a bare fallback length last. Measure the rendered width across breakpoints; do not eyeball it.
  3. Intrinsic-width descriptors must equal the file's real decoded width. photo-1200.jpg 640w when the file is 1200px poisons the selection math — the browser thinks 640w is enough and serves blur, or the opposite. Verify each w/x label against the actual pixel width of the file it points at.
  4. The hero/LCP image must not be loading="lazy". Lazy delays discovery and typically regresses LCP. Use loading="eager" (or omit loading) plus fetchpriority="high" so it wins network priority from discovery. Cap fetchpriority="high" at 1-2 elements per page — if everything is high, nothing is — and keep genuinely below-the-fold images loading="lazy".
  5. Every <img> needs width + height attributes (or a reserved aspect-ratio) or it shifts layout when the file arrives (CLS). An image sized only in CSS (width: 100%; height: auto) with no width/height attributes collapses to height 0 until it downloads, then shoves the content below it down the page. Keep the attributes so the browser derives an aspect-ratio and reserves the box up front, and pair them with CSS max-width: 100%; height: auto to stay responsive. Do not override with a fixed CSS height (it distorts the ratio) or drop the attributes (the collapse returns).
  6. Too few candidates. One or two widths in srcset cannot serve DPR 2-3 phones and wide desktops well; provide a spread that brackets the real sizes range. Do not over-file: a fixed-size icon or logo needs no srcset at all.
  7. Descriptor type must match intent. x (density) descriptors are for a fixed display size across DPRs; w (width) descriptors + sizes are for variable layout width. Mixing them, or adding sizes to an x-descriptor srcset (where it is ignored), is a misuse — sizes is only meaningful with w.
  8. <picture> is for art-direction and format fallback, not resolution switching. Use <source media="..."> when the crop/aspect genuinely changes per breakpoint, and <source type="image/avif"> before webp/jpg for format fallback. Each <source> needs its media or type, and a real <img src alt> must close the <picture>. If only the resolution changes, drop <picture> and put srcset/sizes on the <img>.
  9. sizes="auto" is only valid with loading="lazy". On an eager image the value is invalid and browsers fall back to 100vw (over-download). Keep explicit sizes lengths for eager/hero images; only use auto on lazy ones, and keep width/height for the aspect ratio.

Quick probes

Leads, not proof — HTML/JSX tags can span multiple lines, so confirm on the rendered tag before filing. Mechanical validity belongs to the linters below; use these to find candidates to judge.

Installs
1
GitHub Stars
1
First Seen
3 days ago
responsive-image-contracts — voidmatcha/frontend-niche-skills