CSS Accessibility
Contrast, focus rings, reduced motion, and inclusive CSS patterns.
Introduction to Accessible CSS
What You'll Learn
Accessibility (a11y) is not only ARIA attributes—CSS strongly affects perception: contrast, focus visibility, target size, motion, and reading order. This tutorial covers practical patterns you can apply today.
- Color contrast and non-color cues
- Visible focus styles for keyboard users
- Respecting
prefers-reduced-motion - Hit targets, line length, and zoom-friendly layouts
WCAG guidelines provide measurable targets (e.g. contrast ratios). CSS is how you meet many of them without breaking your design system.
Color Contrast & Non-Color Indicators
Theory: Text and interactive elements need sufficient contrast against their background. Do not rely on color alone for errors—add icons, text, or patterns.
Example: Safer “muted” text
/* Prefer darker grays on white; #94a3b8 often fails WCAG AA for body text */
body { color: #0f172a; background: #ffffff; }
.text-muted-a11y { color: #475569; }
.text-error {
color: #b91c1c;
font-weight: 600;
}
.text-error::before {
content: "⚠ ";
}
Focus Visible: Keyboard & Click
Theory: :focus-visible shows a ring for keyboard users while avoiding ugly outlines on every mouse click. Never use outline: none without a replacement.
Example: Focus ring
a:focus-visible,
button:focus-visible {
outline: 3px solid #2563eb;
outline-offset: 2px;
}
Reduced Motion
Theory: Some users experience vestibular disorders or migraines from motion. Honor prefers-reduced-motion: reduce by disabling or shortening animations.
Example
@media (prefers-reduced-motion: reduce) {
*,
*::before,
*::after {
animation-duration: 0.01ms !important;
animation-iteration-count: 1 !important;
transition-duration: 0.01ms !important;
scroll-behavior: auto !important;
}
}
Touch Targets & Readable Line Length
Theory: Interactive controls should be large enough to tap (roughly 44×44 CSS pixels). Long lines of text are hard to read—use max-width on text columns (often 60–75ch).
Example
.btn-touch {
min-height: 44px;
min-width: 44px;
padding: 0.5rem 1rem;
}
.prose {
max-width: 65ch;
line-height: 1.6;
}
Summary
Test with keyboard only, zoom to 200%, and run automated contrast checks. Accessible CSS pairs with semantic HTML: landmarks, headings, and labels do the structural work; your styles make that structure perceivable for everyone.