Skip to main content
ACCESSIBILITY

Text resizing

Draft

Support text resizing up to 200% without loss of content or functionality, as required by WCAG 1.4.4.


How users resize text

There are three primary mechanisms users employ, and your interface must handle all of them:

Browser zoom

Ctrl/Cmd + Plus scales the entire viewport — text, images, and layout. At 200% zoom on a 1440px monitor, the effective viewport becomes 720px. Your layout must reflow to fit this narrower space without horizontal scrolling.


Browser font size setting

Users can change the default font size in their browser settings (e.g., from 16px to 24px). This only affects text sized with relative units (rem, em, %). Text sized with px is unaffected, which is why Arch UI tokens use rem for all typography values.


Operating system text scaling

Both macOS and Windows offer system-wide text scaling settings. These affect rendered font sizes at the OS level and behave similarly to browser font size changes.


Relative units in Arch UI

Why rem over px

Arch UI typography tokens are defined in rem units, not pixels. A rem is relative to the root element's font size (typically 16px by default). When a user increases their browser's base font size, all rem-based text scales proportionally.

TokenValueAt default (16px)At 150% (24px)
--font-size-1000.75rem12px18px
--font-size-2000.875rem14px21px
--font-size-3001rem16px24px
--font-size-4001.25rem20px30px
--font-size-5001.5rem24px36px

Pixel values do not scale with user preferences. If you hardcode font-size: 14px, that text stays at 14px regardless of what the user has configured — defeating their accessibility settings.


When em is appropriate

Use em for values that should scale relative to their parent's font size, not the root. This is useful for:

  • Spacing within text blocks — margins and padding that should grow with the text they surround
  • Icon sizing — icons inline with text that should match the text size
/* Icon scales with surrounding text */
.inline-icon {
width: 1em;
height: 1em;
vertical-align: -0.125em;
}

When px is acceptable

Some values should not scale with text size:

  • Borders — a 1px border should remain 1px regardless of zoom level
  • Shadows — box shadow offsets and blur radii are visual effects, not content
  • Focus outlines — the 2px focus ring should remain consistent for visibility

Arch UI border and shadow tokens use px intentionally for these cases.


Layout reflow

The 320px rule

WCAG 1.4.10 (Reflow) requires that content reflows to fit a 320px-wide viewport without horizontal scrolling. This is equivalent to a 1280px viewport at 400% zoom. Arch UI's layout tokens and grid system are designed with this constraint in mind.

Practical implications:

  • Multi-column layouts must collapse — a 3-column grid at normal zoom should stack to a single column at high zoom levels
  • Navigation must adapt — horizontal nav bars should collapse into a hamburger menu or vertical layout
  • Tables may need horizontal scroll — wide data tables are the one acceptable exception to the no-horizontal-scroll rule, provided they are wrapped in a container with overflow-x: auto

Using the layout tokens

Arch UI's spacing and layout tokens use rem for values that should scale and px for fixed structural values:

/* Padding scales with text — uses rem-based token */
.card {
padding: var(--spacing-400); /* 1rem = scales */
}

/* Border does not scale — uses px-based token */
.card {
border: var(--border-width-100) solid var(--color-border-default); /* 1px = fixed */
}

Responsive typography

Fluid type scaling

For display and heading text that needs to scale between viewport sizes, use CSS clamp() with rem units:

.hero-title {
font-size: clamp(var(--font-size-500), 4vw, var(--font-size-800));
}

This creates text that:

  • Never shrinks below --font-size-500 (protecting readability)
  • Scales with the viewport width between breakpoints
  • Never exceeds --font-size-800 (preventing absurdly large text on wide screens)

Line length

Long lines of text are harder to read, especially for users with cognitive disabilities or dyslexia. Arch UI recommends a maximum line length of 80 characters for body text:

.prose {
max-width: 65ch; /* approximately 65 characters */
}

The ch unit is relative to the width of the "0" character in the current font, making it a natural fit for line-length constraints that scale with text size.


Testing text resizing

Browser zoom test

  1. Open your application in Chrome or Firefox
  2. Press Ctrl/Cmd + Plus to zoom to 200%
  3. Verify:
    • All text is visible without horizontal scrolling
    • No text is clipped or overlaps other elements
    • Interactive elements remain clickable and properly spaced
    • Images and icons scale appropriately
  4. Continue to 400% and verify content reflows to a single column

Font size override test

  1. Open Chrome settings > Appearance > Font size
  2. Set it to "Very large" (24px)
  3. Navigate through your application and verify:
    • All text has actually grown (anything stuck at the same size is using px units)
    • Layout accommodates the larger text without breaking
    • Buttons and form controls expand to fit their text content

Firefox font minimum test

  1. Open Firefox settings > Language and Appearance > Fonts
  2. Set a minimum font size (e.g., 20px)
  3. Verify that no text appears smaller than the minimum

Common mistakes

Fixed-height containers with text

/* Problem: text overflows at larger sizes */
.label {
height: 32px;
overflow: hidden;
}

/* Solution: use min-height or let height be auto */
.label {
min-height: 32px;
}

When text grows, fixed-height containers clip content. Use min-height instead of height, and avoid overflow: hidden on containers that hold text.


Pixel-based media queries

/* Problem: doesn't account for user font size */
@media (max-width: 768px) {
.sidebar { display: none; }
}

/* Better: rem-based breakpoint scales with user preferences */
@media (max-width: 48rem) {
.sidebar { display: none; }
}

A 48rem breakpoint triggers at 768px for users with a default 16px font size, but it triggers at 1152px for users with a 24px font size — which is correct, because those users need the mobile layout earlier.


Truncation without access to full content

Text truncation (text-overflow: ellipsis) hides content. If the full text is important, provide a way to reveal it — a tooltip, an expandable region, or a "show more" control.

// Problem: truncated text with no way to read the full label
<span className="truncate">{longLabel}</span>

// Solution: add a title attribute and ensure focus/hover reveals full text
<span className="truncate" title={longLabel}>
{longLabel}
</span>

Viewport units for font sizing

/* Problem: text size tied to viewport, ignores user preferences */
.heading {
font-size: 5vw;
}

/* Solution: clamp with rem bounds */
.heading {
font-size: clamp(1.5rem, 4vw, 3rem);
}

Viewport-only font sizes (vw, vh) ignore user font size preferences entirely. Always pair viewport units with rem-based minimum and maximum values using clamp().


Quick reference

RequirementRule
Text sizingUse rem or em for all font sizes — never px
Spacing near textUse rem-based tokens for padding and margins
Container heightsUse min-height, not height, for text containers
Layout reflowContent must work at 320px effective width (1280px at 400% zoom)
Line lengthCap body text at 65-80 characters with max-width in ch units
Borders and shadowspx is acceptable for decorative, non-content values
BreakpointsPrefer rem-based media queries over px
Viewport unitsNever use vw/vh alone for font sizes — always use clamp() with rem bounds