← Back to CSS3 Mastery
Advanced15 min read

Accessibility in CSS

Build inclusive interfaces with CSS — focus management, color contrast, motion preferences, screen reader utilities, and accessible form styling.

Focus Visible Styles

Keyboard users depend on visible focus indicators. Never remove outline without providing an alternative. The :focus-visible pseudo-class shows focus rings only for keyboard navigation, not mouse clicks.

Design focus styles that match your brand — a 2px solid outline with offset is the minimum. High-contrast themes may need thicker outlines or double-ring patterns.

  • Never use outline: none without a :focus-visible replacement
  • Test focus order by tabbing through every interactive element
  • Focus styles must meet 3:1 contrast against adjacent colors
:focus-visible {
  outline: 2px solid var(--color-primary);
  outline-offset: 2px;
}

.button:focus-visible {
  box-shadow: 0 0 0 3px rgba(37, 99, 235, 0.4);
  outline: none;
}

Color Contrast

WCAG AA requires 4.5:1 contrast for normal text and 3:1 for large text (18px+ or 14px+ bold). AAA level requires 7:1 and 4.5:1 respectively. Use tools like WebAIM Contrast Checker during design.

Do not rely on color alone to convey information. Pair color changes with icons, text labels, or patterns. Error states should include an icon and message, not just red borders.

:root {
  --color-text: #1e293b;        /* 12.6:1 on white */
  --color-text-muted: #64748b;  /* 4.6:1 on white */
  --color-error: #dc2626;
  --color-success: #16a34a;
}

Screen Reader Utilities

The .sr-only (screen reader only) class hides content visually while keeping it available to assistive technology. Use it for icon buttons that need text labels, skip links, and supplementary context.

Skip navigation links let keyboard users bypass repetitive content. Position them off-screen and reveal on focus so they are available but not visually intrusive.

.sr-only {
  position: absolute;
  width: 1px; height: 1px;
  padding: 0; margin: -1px;
  overflow: hidden;
  clip: rect(0, 0, 0, 0);
  white-space: nowrap;
  border: 0;
}

.skip-link:focus {
  position: fixed;
  top: 1rem; left: 1rem;
  z-index: 9999;
  padding: 0.75rem 1.5rem;
  background: var(--color-primary);
  color: white;
}

Motion and Vestibular Safety

The prefers-reduced-motion media query detects users who have requested reduced motion in their OS settings. Disable or simplify animations, parallax effects, and auto-playing transitions.

Provide meaningful alternatives — replace slide-in animations with instant appearance or simple opacity fades. Never auto-play animations that cannot be paused.

  • Test with reduced motion enabled in macOS or Windows settings
  • Auto-scrolling content must have a pause/stop control
  • Parallax and scroll-jacking are especially problematic for vestibular disorders
@media (prefers-reduced-motion: reduce) {
  .carousel {
    scroll-behavior: auto;
  }
  .animated-element {
    animation: none;
    transition: none;
  }
}

Target Size and Touch Accessibility

WCAG 2.2 requires touch targets of at least 24×24 CSS pixels, with 44×44 recommended for mobile. Use min-height and min-width on interactive elements, or padding to expand the clickable area.

Spacing between targets prevents mis-taps. A minimum 8px gap between adjacent buttons on mobile reduces accidental activations.

.icon-button {
  min-width: 44px;
  min-height: 44px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
}

.action-group {
  display: flex;
  gap: 0.5rem;
}

High Contrast and Forced Colors

The prefers-contrast media query detects when users request higher contrast. The forced-colors mode (Windows High Contrast) overrides your color choices with system colors.

Use system color keywords (Canvas, CanvasText, LinkText) in forced-colors mode. Test with Windows High Contrast themes to ensure your UI remains functional.

@media (forced-colors: active) {
  .button {
    border: 2px solid ButtonText;
    background: ButtonFace;
    color: ButtonText;
  }
}

Get In Touch


Ready to discuss your next project? Drop me a message.