Stop iOS zooming the page on every tap into a field
tests / pest (push) Successful in 7m9s Details
tests / assets (push) Successful in 20s Details
tests / release (push) Successful in 4s Details

Safari zooms when a focused input is smaller than 16px, and then leaves the page
zoomed — so on an iPhone every form throws the layout about, and the way back is
a pinch. The usual fix is the meta-viewport switch, which suppresses the zoom by
disabling pinch-zoom entirely: it takes a real accessibility feature away from
everyone to solve a cosmetic problem for some. Sizing the fields at 16px on
touch devices removes the reason instead.

!important on purpose: it has to beat every text-size utility on every field in
the application, and a rule that loses to `text-sm` on one form is worth
nothing. Checkboxes and radios are left alone — no text to inflate, and sizing
them there breaks the box.

Also -webkit-text-size-adjust, so iOS stops inflating body copy in landscape.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
feat/portal-design tested-20260727-1306-be082b7
nexxo 2026-07-27 14:59:12 +02:00
parent b85c12e8b9
commit be082b7bf9
1 changed files with 65 additions and 0 deletions

View File

@ -24,6 +24,8 @@
font-family: var(--font-sans);
-webkit-font-smoothing: antialiased;
text-rendering: optimizeLegibility;
/* Stops iOS inflating body text when the phone is turned to landscape. */
-webkit-text-size-adjust: 100%;
}
body {
@ -51,6 +53,69 @@
}
}
@layer components {
/* Registration marks the corner crosses on a printed form. A pseudo
element rather than markup: they are decoration, and a screen reader
announcing "plus, plus" on every panel would be noise. Tailwind cannot
express ::before content, so this is the one place it lives in CSS. */
.doc-marks {
position: relative;
}
.doc-marks::before,
.doc-marks::after {
content: "+";
position: absolute;
font-family: var(--font-mono);
font-size: 0.78rem;
line-height: 1;
color: var(--border-strong);
pointer-events: none;
}
.doc-marks::before {
top: -6px;
left: -6px;
}
.doc-marks::after {
bottom: -6px;
right: -6px;
}
/* The rule that precedes an eyebrow label, in the accent. Same reasoning:
decorative, and it has to sit on the text baseline of a flex row. */
.doc-eyebrow::before {
content: "";
display: block;
width: 22px;
height: 1px;
background: var(--accent);
flex: none;
}
}
/* iOS zooms the whole page when a field smaller than 16px takes focus, and
* then leaves the page zoomed every tap into a form throws the layout about.
*
* There is no way to decline it: the meta-viewport switch that used to suppress
* it also kills pinch-zoom, which takes a genuine accessibility feature away
* from everyone to fix a cosmetic problem for some. Making the fields 16px on
* touch devices removes the reason instead.
*
* !important, and deliberately: this has to beat every text-size utility on
* every field in the application, and a rule that loses to `text-sm` on one
* form is worth nothing. Checkboxes and radios are excluded they have no text
* to inflate and sizing them here would break their box.
*/
@media (pointer: coarse) {
input:not([type='checkbox']):not([type='radio']),
select,
textarea {
font-size: 16px !important;
}
}
@media (prefers-reduced-motion: reduce) {
*,
*::before,