Blog ·
Two families of five
Five pages needed an illustration and the house style turned out not to exist. A pixel count settled it, and an orange ribbon lost to a measurement of zero.
By Provibr
Five pages on our site had no illustration: the documentation index, the tutorials index, the partners page, the blog index and the contact page. Everything else had one. The task was to draw five pictures that look like they belong.
Look like they belong to what, exactly, is the question, and it is not one you can answer by looking. Ten existing images, viewed one at a time on ten different pages over several months, produce a confident impression of a house style. That impression is worth nothing, and we have the count to prove it.
The style did not exist
A short script walked all ten images on a canvas and counted the dark pixels: luminance at or below 110, alpha at or above 200, quantised to sixteen levels so that anti-aliasing does not produce a thousand near-identical colours.
The result was two groups of five, with no overlap at all.
| Group | Outline colour | Neutral black pixels |
|---|---|---|
| The five feature illustrations | a deep navy, dominant, with two blues alongside | zero |
| The five comparison illustrations | neutral black and near black, with greys | many |
Five to five. There is no majority. Had somebody eyeballed it, they would have picked whichever group they had looked at most recently and produced a sixth image that matched half the site.
The new five follow the first group, and the reason is not the count. The comparison images are a sub family with their own component, their own aspect ratio and their own place in the product; they are a different kind of page doing a different job. The new illustrations sit next to the first group, so they draw like the first group. The measurement did not make the decision. It made the decision possible, by replacing a feeling about a house style with two facts about two sets.
A colour that is not in the stylesheet is an invented colour
The navy that dominates the first group appears nowhere in our stylesheet. It is a colour that arrived with those images and has no name in the design system.
Copying it into five new files would have been the exact thing this round was supposed to avoid: a value that exists only because somebody sampled a pixel. So the new images use the token whose value is nearest to it and which sits in the same family as the brand colour. It is not identical. It is defensible, and it moves if the system moves.
The first draft also had an orange reading ribbon on the documentation image, using the accent colour, because a ribbon is orange. A second count settled that too: of the ten existing illustrations, across 1.79 million opaque pixels, the number with any warm pixel at all is zero. Not few, zero. One orange element would have made the new drawing the only warm thing on the site, which is a decision somebody may want to make deliberately one day and is not a decision a ribbon should make on its own.
White is where the eye lands
The last shared property is one that nobody had written down and all ten obey: each image has exactly one white plane, and it is where the eye goes. The front of a vault, the inside of a shield, the tiles around a hub.
Four of the five new drawings picked that up naturally, because a sheet of paper, an article, a letter and a play button are white things. The partners image did not: two shades of blue, no white anywhere.
It looked fine on the partners page. It was obviously wrong on a contact sheet, which is a single generated page that puts all fifteen images side by side on the real background colour. One drawing in a row of fifteen that has no focal plane reads as flatter than the rest, immediately, and reads as nothing at all when you look at it alone. The left hexagon now sits on the surface colour.
If you are going to make a set, look at the set. Individual pages are the wrong review surface for a property that only exists in comparison.
A line drawn before the shapes is a line you do not see
The first version of the partners image had a connecting line between the two hexagons: a single horizontal stroke, 433 pixels wide, declared before the two shapes.
Painters' order did the rest. The hexagons covered the middle of it, leaving two stubs sticking out at the sides, and because the right hexagon had a fill opacity slightly below one, the covered part showed through as a ghost stripe across it. Two defects from one ordering mistake, and both of them look like a rendering problem rather than a source problem.
The connection is now the overlap itself, clipped to the intersection of the two shapes, and there is no partial transparency anywhere in the file. That is a better drawing as well as a working one: the shared area between two partners is the idea, and a line between them was a weaker way of saying it.
Two hyphens end an XML comment
Every one of these files carries comments explaining the geometry, and comments in an SVG travel to the browser. Measured on the first version: of 10,160 bytes across the five files, 5789 were comment. Fifty seven per cent of what we would have shipped was an explanation of what we shipped.
The explanation now lives in the component that references the images, where it is at least as useful and reaches nobody's browser. That is a general point about the difference between source comments and asset comments: one is free and one is payload.
The second point is a rule rather than a measurement, and it is the sort of rule you only need once. A double hyphen terminates an XML comment. Referring to a CSS custom property by its name inside an SVG comment therefore ends the comment early, in the middle of a sentence, and the rest of that sentence becomes markup. The file then fails to parse, and an SVG that fails to parse does not produce an error message. It produces a 200 response and an empty image.
The current five contain no double hyphens inside any comment and all five parse as valid XML. The failure mode is real; the specific incident is not something I can hand you a measurement for, because that state was never committed.
Alt text is not a design decision
An illustration that says nothing the adjacent heading does not already say is decoration, and the accessibility answer for decoration is an empty alt attribute, so that a screen reader does not read out "vault with key" next to a heading about credentials staying on your own host. That reasoning is correct and we followed it for a long time.
It is also not the whole picture, because a crawler cannot tell decoration from content. An SEO audit counts an empty alt as a missing alt, and a report full of missing alt attributes is a report nobody reads.
So every illustration now carries a short description from the translation catalogue, one description per image rather than per placement, since the same drawing means the same thing on two different pages. The guard requires a non-empty alt on every illustration, which means hiding one from the accessibility tree is not an option somebody can quietly take. A new illustration needs a description in all nine languages before it can ship.
Zero shift, and the counterproof
The width and height on each image are the dimensions of the file's own view box, and they are there for exactly one reason: so the browser reserves the space before the bytes arrive. The visible width comes from classes and has nothing to do with those numbers.
Cumulative layout shift across forty five page states measured 0.00000, which is a number that means nothing on its own. Any measurement that reports a perfect zero has to answer the question of whether it was looking.
So the same run was repeated with the dimensions stripped out and a 1500 millisecond delay injected in front of the images. Thirteen of fifteen states shifted. The two that did not sit in the shortest cell of a grid, where the image cannot change the row height whatever it does, so their zero is structural rather than accidental. That was checked individually rather than waved away, because two unexplained zeros in a counterproof is exactly where a real gap would hide.
There is one more mechanical detail worth stating, since it is easy to get wrong in the other direction: these images bypass the framework's image optimiser entirely. That is not laziness. The optimiser refuses SVG unless a specifically dangerous flag is enabled, so routing them through it would produce a broken image rather than a smaller one.
A finding that was not part of the round
While measuring widths, one utility class on an unrelated page turned out to do nothing at all. It sets a maximum width that is overridden by a class declared later in the stylesheet, so the value has been inert since it was written.
Nobody had noticed, because the element looks reasonable at its actual width. That is the ordinary way dead styling survives: it is not wrong on screen, it is simply not the thing doing the work, and the only way to find it is to measure a property you were already measuring for another reason.
What we would write down
- A house style you have never counted may not exist. Ten images, two families, five each, and every impression of a majority was wrong.
- A measurement makes a decision possible; it does not make it. Neither group was larger; the new images follow the feature illustrations because of what kind of page they are on.
- A colour sampled from a pixel is an invented colour. Use the nearest token and accept that it is not identical.
- Zero is a strong answer. No warm pixel in 1.79 million settles an argument about an orange ribbon faster than taste does.
- Review a set as a set. Properties that only exist in comparison are invisible on an individual page.
- Declare a connector after the things it connects, or it will be covered, and partial transparency will make the mistake look like a renderer bug.
- Comments in an asset are payload. More than half of what we nearly shipped was explanation.
- Invalid XML in an SVG is an empty image, not an error. There is no message to search for.
- Empty alt is correct for a human and missing for a crawler. Pick the trade deliberately and enforce it in a test.
- A perfect zero needs a counterproof. Break the thing on purpose and check that the number moves.
For clarity about what this is: the five images are live in nine languages with descriptions, the counts come from a canvas run on the real files, and everything was measured against a development server rather than a production build. There is no dark theme to check against, which was verified rather than assumed: with dark emulated, the capture is byte for byte identical to the light one.
From the platform work on Provibr. A layout defect that produced zero pixels of overflow is in a bar narrower than its window, and what nine languages do to a set of fixed controls is in sixteen thousand keys and nine languages.