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: "⚠ ";
}
Sample output: Error state is visible even to users who cannot distinguish red/green differences.

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;
}
Sample output: Tab navigation clearly shows which control is active.

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;
    }
}
Sample output: Essential transitions become nearly instant; decorative motion is suppressed.

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;
}
Sample output: Buttons are easier to tap on phones; paragraphs stay within comfortable reading width.

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.