Millions of people worldwide live with various visual impairments. Not all of them use screen readers - many simply need larger text. WCAG 1.4.4 “Resize Text” defines the minimum requirements your website must meet to be accessible to this group of users.
What is WCAG 1.4.4?
WCAG 1.4.4 “Resize Text” is a Level AA success criterion, which is required by most accessibility regulations, including the European Web Accessibility Directive and the Americans with Disabilities Act (ADA).
The requirement states: Text (except for captions and images of text) can be resized up to 200% without assistive technology and without loss of content or functionality.
This means users must be able to:
- Enlarge text using built-in browser features
- Not lose access to any content
- Maintain full website functionality
| WCAG Level | Zoom | Criterion |
|---|---|---|
| A | 100% | No requirements |
| AA | 200% | WCAG 1.4.4 Resize Text |
| AAA | 400%+ | WCAG 1.4.10 Reflow |
Exceptions
The criterion does not apply to:
- Captions - text in videos
- Images of text - text embedded in graphics (though these should be avoided)
Why Text Resizing Matters
Diverse User Needs
People who need larger text aren’t just blind users with screen readers. They include:
- Low vision users - they can see but need magnification
- Seniors - aging affects eyesight
- Users with temporary issues - eye strain, migraines, poor lighting conditions
- Mobile users - small screens in bright sunlight
Legal Requirements
The European Accessibility Act extends accessibility requirements to the private sector from 2025. In the US, ADA compliance increasingly requires WCAG 2.1 Level AA. Organizations face legal risks and potential lawsuits for non-compliance.
SEO Impact
Google increasingly rewards accessible websites. Good accessibility practices often overlap with good website optimization practices - responsiveness, semantic HTML, and readable typography.
CSS Units: The Key to Text Scaling
Choosing the right CSS units for text size is fundamental to accessibility. Units are divided into absolute and relative.
Absolute Units - Avoid for font-size
/* Wrong - doesn't scale with user preferences */
body {
font-size: 16px;
}
h1 {
font-size: 32px;
}
Pixels (px) and points (pt) are absolute units. This means text sized at 16px will always be exactly 16 pixels, regardless of user’s browser settings.
The problem: When a user changes the default text size in browser settings (e.g., from 16px to 20px), pixel-based text won’t scale.
Relative Units - Preferred
/* Good - scales with user preferences */
:root {
font-size: 100%; /* Respects browser settings */
}
body {
font-size: 1rem;
}
h1 {
font-size: 2.5rem;
}
| Unit | Type | Relative to | Scales | Recommendation |
|---|---|---|---|---|
px | Absolute | - | No | Avoid for font-size |
pt | Absolute | - | No | Print only |
rem | Relative | Root element | Yes | Preferred |
em | Relative | Parent element | Yes | For components |
% | Relative | Parent element | Yes | Alternative |
vw/vh | Viewport | Window width/height | Partially | Carefully, with clamp() |
Practical Typography System
/* Base size - respects user preferences */
:root {
font-size: 100%; /* Default 16px, but scales */
}
body {
font-size: 1rem;
line-height: 1.6;
}
/* Headings in rem - proportional scaling */
h1 { font-size: 2.5rem; } /* 40px at default */
h2 { font-size: 2rem; } /* 32px */
h3 { font-size: 1.5rem; } /* 24px */
h4 { font-size: 1.25rem; } /* 20px */
/* Helper text */
small, .text-sm { font-size: 0.875rem; } /* 14px */
Fluid Typography with clamp()
The clamp() function allows smooth text scaling between minimum and maximum values:
/* Fluid typography - smoothly scales with viewport */
h1 {
/* min: 1.5rem, preferred: 4vw + 1rem, max: 3rem */
font-size: clamp(1.5rem, 4vw + 1rem, 3rem);
}
p {
font-size: clamp(1rem, 2vw + 0.5rem, 1.25rem);
}
Note: When using viewport units (vw, vh), always use clamp() with rem values to ensure minimum and maximum sizes that scale with user preferences.
Viewport Meta: What to Avoid
The <meta name="viewport"> tag controls how the page is displayed on mobile devices. Incorrect configuration can completely block zoom capability.
Correct Configuration
<meta name="viewport" content="width=device-width, initial-scale=1">
That’s all you need. This configuration:
- Sets width to device width
- Starts at 1:1 scale
- Does not block zoom capability
Errors Violating WCAG 1.4.4
<!-- ERROR: Completely blocks pinch-to-zoom -->
<meta name="viewport" content="width=device-width, initial-scale=1, user-scalable=no">
<!-- ERROR: Limits maximum zoom to 100% -->
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1">
<!-- ERROR: Combination of both problems -->
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no">
Why This Is a Problem
user-scalable=no- completely disables pinch-to-zoom gesture on iOSmaximum-scale=1- limits maximum zoom to 100%- On iOS Safari, these restrictions are enforced
- Android Chrome ignores
user-scalable=nosince version 32, but don’t rely on this
Common Argument (and Why It’s Wrong)
“I need to block zoom because the form breaks when magnified”
This isn’t a solution - it’s hiding the problem. If a form doesn’t work at 200% zoom, the form needs fixing, not blocking accessibility.
Text Containers: Overflow and Height
Another common problem is containers with limited height that clip text when zoomed.
Problem: Fixed Height
/* Wrong - text will be clipped when zoomed */
.card {
height: 200px;
overflow: hidden;
}
.card-description {
max-height: 80px;
overflow: hidden;
}
At 200% zoom, text in a fixed-height container will be clipped, and users will lose access to part of the content.
Solution: Flexible Containers
/* Good - container grows with text */
.card {
min-height: 200px; /* Minimum, but can grow */
/* No overflow: hidden */
}
.card-description {
/* No height restrictions */
}
Exception: Intentional Truncation with Full Access
Sometimes you need to show only a text excerpt (e.g., article preview). This is acceptable if the full content is accessible elsewhere:
/* OK - preview with link to full content */
.article-preview {
display: -webkit-box;
-webkit-line-clamp: 3;
-webkit-box-orient: vertical;
overflow: hidden;
}
<article class="article-preview">
<p>Beginning of article that might be long...</p>
</article>
<a href="/full-article/">Read more</a>
Problematic Patterns
Avoid these patterns without alternative access to content:
/* Wrong - clips text without warning */
.bio {
height: 100px;
overflow: hidden;
}
/* Wrong - tooltip disappears when zoomed */
.tooltip {
position: absolute;
max-height: 50px;
overflow: hidden;
}
Responsive Design and Accessibility
Responsive Web Design and accessibility go hand in hand, but breakpoints alone aren’t enough.
Media Queries Don’t Replace Relative Units
/* This is NOT a solution for WCAG 1.4.4 */
@media (max-width: 768px) {
body { font-size: 14px; } /* Still px! */
}
@media (max-width: 480px) {
body { font-size: 12px; }
}
The code above changes text size on different devices but still uses pixels - users can’t increase text beyond the specified values.
Correct Approach
/* Base size in relative units */
body {
font-size: 1rem;
}
/* Increase for larger screens - still in rem */
@media (min-width: 1200px) {
body {
font-size: 1.125rem;
}
}
Testing at Different Zoom Levels
Remember that 200% zoom isn’t the same as a smaller screen:
- 768px breakpoint - browser on a tablet
- 200% zoom - user with magnification on desktop
At 200% zoom on a 1920px screen, the effective width is 960px. But this isn’t the same as a tablet - the user has a mouse, larger physical screen, and different expectations.
Implementing Font Size Controls
While browsers offer built-in zoom features, some websites implement their own A+/A- controls. This can help users unfamiliar with keyboard shortcuts.
Accessible HTML Pattern
<div class="font-controls" role="group" aria-label="Text size">
<button
type="button"
id="font-decrease"
aria-label="Decrease text size"
>
A-
</button>
<button
type="button"
id="font-reset"
aria-label="Reset to default text size"
>
A
</button>
<button
type="button"
id="font-increase"
aria-label="Increase text size"
>
A+
</button>
</div>
JavaScript with Persistence
const FONT_SIZES = ['87.5%', '100%', '112.5%', '125%', '150%'];
const DEFAULT_INDEX = 1; // 100%
const STORAGE_KEY = 'userFontSize';
let currentIndex = DEFAULT_INDEX;
function setFontSize(index) {
currentIndex = Math.max(0, Math.min(index, FONT_SIZES.length - 1));
document.documentElement.style.fontSize = FONT_SIZES[currentIndex];
localStorage.setItem(STORAGE_KEY, currentIndex.toString());
// Update button states
updateButtonStates();
}
function updateButtonStates() {
document.getElementById('font-decrease').disabled = currentIndex === 0;
document.getElementById('font-increase').disabled = currentIndex === FONT_SIZES.length - 1;
}
function loadSavedFontSize() {
const saved = localStorage.getItem(STORAGE_KEY);
if (saved !== null) {
setFontSize(parseInt(saved, 10));
}
}
// Event listeners
document.getElementById('font-decrease').addEventListener('click', () => {
setFontSize(currentIndex - 1);
});
document.getElementById('font-reset').addEventListener('click', () => {
setFontSize(DEFAULT_INDEX);
});
document.getElementById('font-increase').addEventListener('click', () => {
setFontSize(currentIndex + 1);
});
// Load saved size on startup
loadSavedFontSize();
Alternative: CSS Custom Properties
:root {
--font-scale: 1;
}
body {
font-size: calc(1rem * var(--font-scale));
}
h1 {
font-size: calc(2.5rem * var(--font-scale));
}
function setFontScale(scale) {
document.documentElement.style.setProperty('--font-scale', scale);
localStorage.setItem('fontScale', scale);
}
How to Test WCAG 1.4.4
Method 1: Browser Zoom
The simplest and most important testing method:
- Open the page in your browser
- Press Ctrl + Plus (Windows/Linux) or Cmd + Plus (Mac)
- Zoom to 200% (usually 4-5 clicks)
- Check every page and feature
What to verify:
- Is all text visible?
- Is there no horizontal scrolling?
- Does navigation work?
- Do forms function correctly?
- Are buttons clickable?
Method 2: System Settings
Also test with increased default text size:
Windows:
- Settings → Accessibility → Text size
- Move slider to larger size
macOS:
- System Preferences → Accessibility → Display
- Enable “Use keyboard shortcuts to zoom”
Browser (Chrome):
- Settings → Appearance → Font size
- Change from “Medium” to “Very Large”
Automated Tools
| Tool | Type | Description |
|---|---|---|
| WAVE | Extension/online | Detects accessibility issues |
| axe DevTools | Chrome extension | Detailed WCAG audit |
| Lighthouse | Built into Chrome | Accessibility audit in DevTools |
| Pa11y | CLI | Automated testing for CI/CD |
WCAG 1.4.4 Checklist
Use this list for verification:
- Text can be resized to 200% without content loss
- No
user-scalable=noin viewport meta - No
maximum-scale=1in viewport meta - Text sizes use relative units (
rem,em,%) - Text containers don’t have fixed height with
overflow: hidden - Navigation works at 200% zoom
- Forms are functional at 200% zoom
- No horizontal scrolling at 200% zoom
Summary
WCAG 1.4.4 requires that text can be resized to 200% without loss of content or functionality. Key principles:
- Use relative units -
remandeminstead ofpxfor text size - Don’t block zoom - avoid
user-scalable=noandmaximum-scale=1in viewport meta - Flexible containers - don’t restrict height of text containers
- Test regularly - check your site at 200% zoom
- Remember legal requirements - Level AA is mandatory for many organizations
Accessibility isn’t just a legal requirement - it’s respect for all users of your website.
Sources
-
W3C - Understanding Success Criterion 1.4.4: Resize text https://www.w3.org/WAI/WCAG21/Understanding/resize-text.html
-
WebAIM - Fonts https://webaim.org/techniques/fonts/
-
MDN - CSS values and units https://developer.mozilla.org/en-US/docs/Learn/CSS/Building_blocks/Values_and_units
-
Yale Usability - Zoom and Resizing Text https://usability.yale.edu/web-accessibility/articles/zoom-resizing-text
-
Deque - Understanding WCAG 1.4.4 https://www.deque.com/blog/accessible-text-resizing-in-css/
-
MDN - clamp() function https://developer.mozilla.org/en-US/docs/Web/CSS/clamp


