Depends on #14 and on #34.
#6 sets cumulative layout shift to exactly zero and #35 measures it in a
headless browser. Measuring is the honest last line and it is the expensive one:
it needs a browser to start, the built output served, and it reports the symptom
after the fact on a runner whose timing moves. The usual cause is one thing, and
it is a property of the produced markup rather than of the run: an image whose
size the browser only learns once the bytes have arrived, which is why everything
below it moves when they do.
That is refusable by reading the output, so it is refused there, and the browser
run stays as the thing that catches what a grep cannot see.
There is nothing to refuse today, which is the argument for landing the rule now
rather than after there is:
curl -sS https://flowfin.dev/ https://flowfin.dev/design-system.html | grep -c -i '<img'
0
Run 2026-08-08. The first image the project publishes is the icon #69 has the
build produce, and whether there are others at all is entry 5 of #7. On either
answer the rule is cheaper held from the first image than retrofitted across
twelve generated pages, and it costs nothing while the count is zero.
The rule: every image in the built output carries its own width and height, and
anything that reserves space for an image reserves it from the same numbers, so
one file cannot disagree with the box drawn for it. A produced page with an
image element missing either attribute reds the invariant gate in #14, and the
failure names the page, the file and the attribute rather than reporting that
something about the markup was wrong.
The dimensions come from the file rather than from a template. A number typed
beside an image is a second copy of a fact the file already carries, and the
first crop makes it wrong in the direction that reserves the wrong box, which is
the failure this rule exists to prevent rather than a smaller version of it.
Done when
The invariant gate carries a row refusing an image element in dist/ without
both dimensions; a fixture page with one attribute removed reds it and names the
page, the file and the missing attribute; the same page with the attribute
restored passes; and the dimensions written into the output are read from the
image file rather than from a template.
Depends on #14 and on #34.
#6 sets cumulative layout shift to exactly zero and #35 measures it in a
headless browser. Measuring is the honest last line and it is the expensive one:
it needs a browser to start, the built output served, and it reports the symptom
after the fact on a runner whose timing moves. The usual cause is one thing, and
it is a property of the produced markup rather than of the run: an image whose
size the browser only learns once the bytes have arrived, which is why everything
below it moves when they do.
That is refusable by reading the output, so it is refused there, and the browser
run stays as the thing that catches what a grep cannot see.
There is nothing to refuse today, which is the argument for landing the rule now
rather than after there is:
Run 2026-08-08. The first image the project publishes is the icon #69 has the
build produce, and whether there are others at all is entry 5 of #7. On either
answer the rule is cheaper held from the first image than retrofitted across
twelve generated pages, and it costs nothing while the count is zero.
The rule: every image in the built output carries its own width and height, and
anything that reserves space for an image reserves it from the same numbers, so
one file cannot disagree with the box drawn for it. A produced page with an
image element missing either attribute reds the invariant gate in #14, and the
failure names the page, the file and the attribute rather than reporting that
something about the markup was wrong.
The dimensions come from the file rather than from a template. A number typed
beside an image is a second copy of a fact the file already carries, and the
first crop makes it wrong in the direction that reserves the wrong box, which is
the failure this rule exists to prevent rather than a smaller version of it.
Done when
The invariant gate carries a row refusing an image element in
dist/withoutboth dimensions; a fixture page with one attribute removed reds it and names the
page, the file and the missing attribute; the same page with the attribute
restored passes; and the dimensions written into the output are read from the
image file rather than from a template.