Direct answer: 24 of 25 homepages were measurable (E13 returned 502), covering 1,372 text elements and 25,879 characters. The character-weighted median is 14px; four sites sit at 12px (E01, E04, E11, E29), ten at 14px, four at 16px and E20 reaches 20px. Five sites contain text under 12px (33 elements, 724 characters), the smallest long text is 8.3px (E18), and 20 of 24 sites have at least one long text with line-height under 1.4.
A small font is not automatically a failure: 12px can work for dates, legal text or secondary labels, but long body copy at 12px is visibly small on a phone. This article treats under 12px and line-height under 1.4 as screening signals.
Method: read computed sizes at 390x844
On 2026-11-09 between 21:54 and 21:58 we opened the same 25 homepages one tab at a time with headless Chrome 124 and the DevTools Protocol: 390x844 at DPR 1 with a desktop UA, waiting 2.5 seconds after readyState reached complete. For each visible element we read only its direct text nodes (at least two characters) and took the computed fontSize and lineHeight. Elements whose ancestor tag or class contains header, footer, nav, menu, breadcrumb or copyright were excluded to approximate the body area.
| Rule | Definition | Boundary |
|---|---|---|
| Text element | Visible, at least 2x2px, with at least two direct text characters | Direct text nodes only; nested spans split into elements |
| Font size | Computed CSS px from getComputedStyle | No browser zoom or OS font scaling |
| Weighted median | Every character votes once by its font size; the middle value | Long paragraphs weigh more than labels |
| Longest text block | The visible element with the most direct characters | May be a heading, list or label, not necessarily a paragraph |
| Under 12px | Font size below 12px | Screening threshold, not a WCAG minimum |
| Line-height ratio | line-height / font-size below 1.4 for at least ten characters | Headings are included; not body-only |
| Body approximation | Exclude nav, footer, menu, breadcrumb and copyright ancestors by tag/class | Class matching is a heuristic and may exclude body content |
Results: median 14px, four sites at 12px
| Weighted median | Sites | Which |
|---|---|---|
| 12px | 4 | E01, E04, E11, E29 |
| 14px | 10 | E02, E03, E06, E09, E12, E17, E19, E25, E28, E30 |
| 14.6px | 1 | E18 |
| 15-15.2px | 3 | E08, E22, E26 |
| 16-16.6px | 5 | E14, E16, E23, E24, E27 |
| 20px | 1 | E20 |
Five sites declare a 12px body font; 14 sites use 14px, three use 16px and the rest are fractional (14.625 and 16.64). The longest text block is 12px on three sites (E04, E11, E29), 14px on 11 sites and 16px on five; E20's 298-character block is 20px. A 12px median does not mean the whole page is 12px: E01's longest block is a 16px intro, but 10px news summaries add up to 467 characters and pull the weighted median down.
Site detail (E13 returned 502 and is omitted):
| Site | Median | Longest | <12px | Chars <12 | Line-height <1.4 |
|---|---|---|---|---|---|
| E01 | 12 | 16 | 14 | 467 | 10 |
| E02 | 14 | 14 | 0 | 0 | 0 |
| E03 | 14 | 14 | 1 | 72 | 25 |
| E04 | 12 | 12 | 0 | 0 | 11 |
| E06 | 14 | 14 | 0 | 0 | 12 |
| E08 | 15 | 14 | 0 | 0 | 4 |
| E09 | 14 | 14 | 0 | 0 | 7 |
| E11 | 12 | 12 | 0 | 0 | 2 |
| E12 | 14 | 14 | 0 | 0 | 0 |
| E14 | 16 | 16 | 0 | 0 | 20 |
| E16 | 16 | 16 | 0 | 0 | 0 |
| E17 | 14 | 14 | 0 | 0 | 12 |
| E18 | 14.6 | 14.6 | 12 | 86 | 1 |
| E19 | 14 | 14 | 0 | 0 | 1 |
| E20 | 20 | 20 | 0 | 0 | 4 |
| E22 | 15 | 15 | 0 | 0 | 11 |
| E23 | 16 | 16 | 1 | 11 | 6 |
| E24 | 16 | 16 | 0 | 0 | 7 |
| E25 | 14 | 14 | 5 | 88 | 12 |
| E26 | 15.2 | 14.9 | 0 | 0 | 21 |
| E27 | 16.6 | 16.6 | 0 | 0 | 3 |
| E28 | 14 | 14 | 0 | 0 | 16 |
| E29 | 12 | 12 | 0 | 0 | 1 |
| E30 | 14 | 14 | 0 | 0 | 0 |
Text under 12px: 33 elements, 724 characters
Five sites contain text below 12px, 33 elements and 724 characters in total; ten of those elements carry at least 20 characters. E01 is the largest: 14 elements and 467 characters, mostly 10px news summaries. E18's 8.3px date labels, E25's five 6.5-10px English taglines, E03's 11px map attribution and E23's 8.6px tagline also count.
| Site | <12px elements | Characters | Smallest long text | What we saw |
|---|---|---|---|---|
| E01 | 14 | 467 | 10px | 10px news summary paragraphs |
| E18 | 12 | 86 | 8.3px | List dates and English labels |
| E25 | 5 | 88 | 10px | English taglines and secondary text |
| E03 | 1 | 72 | 11px | Map attribution |
| E23 | 1 | 11 | 8.6px | Brand tagline |
Line-height: 20 of 24 sites have at least one block under 1.4
For visible text of at least ten characters, the line-height / font-size ratio is below 1.4 on 20 sites, 186 elements in total. E03 has 25, E26 21, E14 20 and E28 16; E02, E12, E16 and E30 have none. Tight leading makes long copy easier to lose one's place on a small screen; headings are included, so this is a screening check rather than a body-only verdict.
Acceptance checklist: body, secondary text and leading separately
- Prefer at least 14px for body copy. Reserve 12px for dates, legal text and secondary labels; do not leave long paragraphs at 10-12px.
- Use 1.5-1.7 line-height. A small font with 1.2 leading makes long copy tighter; fix paragraphs before labels.
- Check the character-weighted figure. Let long paragraphs represent body copy instead of averaging dozens of small labels.
- Look at a real 390px viewport. Browser zoom is no substitute for mobile type; see the mobile viewport pilot.
- Check tap targets together with type. Small text often sits beside small targets; see the 390px tap-target audit.
Limitations
- The body area is approximated by excluding ancestors whose tag or class contains nav/header; this heuristic may remove body content.
- Only direct text nodes are read; nested spans split into elements, so length and weighted median depend on DOM structure.
- Computed CSS px only: no browser zoom, OS font scaling or user styles; one snapshot.
- Text in images, Canvas and SVG is excluded, as are pseudo-element strings.
- The line-height ratio includes headings and labels, not body paragraphs only; under 1.4 is a screening line.
- 25-site pilot, E13 returned 502 and was not measured; no industry claim.
Data and reproduction
Anonymised data: equipment-homepage-font-size-390-2026.csv (25 rows by 17 columns: text elements, characters, under 12px, line-height, weighted median, longest block, body font and time). The repository keeps docs/research/2026-11-homepage-font-size-390.csv. The weighted median and aggregation live in scripts/font_size_probe.py, with six assertions in scripts/test_content_font_size_probe.py; the CSV contains no site URLs, titles or contact details.
Frequently asked questions
Is 12px always unreadable?
No. Twelve pixels can work for secondary information, dates or legal text; a long body paragraph at 12px is small on a phone. This article uses under 12px as a screening threshold, not as a hard WCAG minimum.
Why weight the median by characters?
Long paragraphs represent body copy better than labels do. Averaging per element would let dozens of tiny labels drown the paragraphs; weighting by characters gives each character one vote.
Where does the 1.4 line-height threshold come from?
A 1.5-1.7 line-height is a common body-copy recommendation, and WCAG 1.4.12 text spacing uses 1.5 as a reference. This article uses under 1.4 as a screening line, not a conformance verdict.
Why exclude header, footer and nav?
The aim is the body area, so ancestors whose tag or class contains header, footer, nav, menu, breadcrumb or copyright are excluded. The class match is a heuristic and may exclude some body content; that is a known boundary.
Why only 24 sites?
E13 returned HTTP 502 during this run and its DOM could not be read; the other 24 rendered and were measured.
Can the data be checked?
Yes. The public CSV has 25 rows and 17 columns (including the failed row), and the aggregation rules live in scripts/font_size_probe.py with six offline assertions; re-measure by sample_id.