CSS Tutorial 0/203 lessons ~6 min read Lesson 144

    WCAG 2.2

    wcag 2.2 wcag 2.2 css conformance maps w3c success criteria to concrete stylesheet decisions — focus visibility, target size, contrast,

    Course progress0%
    Focus
    27 guided sections
    Practice signal
    Examples included
    Career prep
    Interview Q&A included

    Introduction

    WCAG 2.2 CSS conformance maps W3C success criteria to concrete stylesheet decisions — focus visibility, target size, contrast, motion, reflow, and non-color state. Staff engineers treat CSS as part of the accessibility contract: a component is not shippable until its styles pass automated rules and manual keyboard/screen-reader validation.

    Business problem

    Legal and revenue risk: EU Accessibility Act (2025), ADA, and AODA enforcement target visual polish that fails WCAG 2.2 — invisible focus rings, 44×44px touch targets, drag-only interactions styled without keyboard alternatives.

    • Procurement: B2G contracts require WCAG 2.2 AA attestation backed by test evidence.
    • Brand: Public a11y failures on checkout or auth flows generate press and social backlash beyond lawsuit cost.
    • Quality: CSS that breaks zoom (1.4.4) or reflow (1.4.10) fails real users on mobile — not just audit tools.

    Why this feature exists

    WCAG 2.2 (September 2023) adds criteria that CSS directly controls: Focus Not Obscured (2.4.11/2.4.12), Target Size Minimum (2.5.8), Dragging Movements (2.5.7), and Accessible Authentication (3.3.8). CSS cannot fix bad semantics alone, but it can violate criteria without a single line of JavaScript.

    • POUR: Perceivable (contrast, motion), Operable (focus, target size), Understandable (consistent focus), Robust (works with AT + zoom).
    • AA baseline: Most regulations reference Level AA — not AAA sitewide.
    • ACT rules: Standardized automated tests map CSS properties to criteria IDs.

    Browser rendering perspective

    CSS affects the accessibility tree indirectly: `display:none`, `visibility:hidden`, `content-visibility`, and `aria-hidden` (HTML) remove or expose nodes. `:focus-visible` styles determine whether keyboard users can see focus (2.4.7). High contrast mode and forced-colors media query override author styles — design must degrade gracefully.

    • Blink: Focus ring drawn via outline or `:-webkit-focus-ring-color` heuristics when author removes outline.
    • Gecko: `:-moz-focusring` and forced-colors palette substitution.
    • WebKit: Safari 17+ improved `:focus-visible` parity — still test iOS VoiceOver + keyboard.

    Internal browser workflow

    Conformance workflow: Map each UI pattern to WCAG criteria → encode CSS tokens (focus, contrast, motion) → run axe/Lighthouse on rendered pages → manual keyboard + SR spot-check → document exceptions in ACR.

    • Design tokens: `--focus-ring`, `--min-target-size: 44px`, `--motion-safe` variants.
    • Component DoD: Zero critical axe violations; focus visible; 200% zoom reflow.
    • 2.2 deltas: Audit modals for focus obscured by sticky headers; audit drag sliders for keyboard alternative.

    Feature deep dive

    WCAG 2.2 criteria with direct CSS ownership:

    • 1.4.3 / 1.4.11: Text and UI component contrast — token pipeline enforces 4.5:1 / 3:1.
    • 1.4.4 / 1.4.10: Resize text 200%; reflow without horizontal scroll — avoid fixed px widths.
    • 2.4.7 / 2.4.11: Focus visible; focus not obscured by sticky/fixed overlays.
    • 2.5.8: Target size minimum 24×24 CSS px (AA) — prefer 44×44 for touch.
    • 2.3.3: `prefers-reduced-motion: reduce` disables non-essential animation.
    css
    :root {
    --focus-ring: 2px solid #2563eb;
    --focus-offset: 2px;
    --min-target: 44px;
    }
    :focus-visible {
    outline: var(--focus-ring);
    outline-offset: var(--focus-offset);
    }
    @media (prefers-reduced-motion: reduce) {
    *, *::before, *::after {
    animation-duration: 0.01ms !important;
    transition-duration: 0.01ms !important;
    }
    }

    Syntax

    CSS techniques for WCAG 2.2 AA:

    css
    /* Focus not obscured — reserve space for sticky header */
    :root { --header-h: 64px; }
    :focus-visible { scroll-margin-top: var(--header-h); }
    /* Target size — icon buttons */
    .icon-btn {
    min-width: var(--min-target);
    min-height: var(--min-target);
    display: inline-flex;
    align-items: center;
    justify-content: center;
    }
    /* Forced colors / high contrast */
    @media (forced-colors: active) {
    .btn { border: 2px solid ButtonText; }
    }

    Examples

    Modal focus obscured fix: Sticky header with `z-index: 100` covers focused link inside dialog — add `scroll-margin` on focusable elements and ensure dialog `z-index` stacks above chrome.

    css
    .dialog[open] { z-index: 200; }
    .dialog :focus-visible { scroll-margin: 80px 0; }

    Real-world use

    Industry practice: GOV.UK Design System, USWDS, and Carbon publish WCAG-mapped CSS for focus, spacing, and motion. Microsoft Fluent documents forced-colors behavior. EU public sector procurement references EN 301 549 which incorporates WCAG 2.2.

    Real production example

    Design token gate in CI: Style Dictionary exports contrast pairs; custom lint rejects `outline: none` without `:focus-visible` replacement.

    • axe-core: color-contrast, target-size, focus-order rules on Storybook + PR previews.
    • VPAT: Map token names to WCAG criteria in accessibility statement.
    css
    /* stylelint-a11y / eslint-plugin-jsx-a11y companion rules */
    /* Ban: .btn:focus { outline: none; } without :focus-visible block */

    Enterprise use case

    Enterprise design systems ship WCAG 2.2 checklists per component: Button, Link, Modal, Tabs — each documents CSS requirements and known browser exceptions.

    • Legal hold: Audit logs tie release SHA to axe report artifacts.
    • Training: Designers use contrast-approved Figma styles only — no ad-hoc hex outside tokens.

    Accessibility considerations

    This lesson is accessibility. CSS is the enforcement layer for visual WCAG criteria — staff engineers own token contracts, not one-off fixes before launch.

    • Never: `outline: none` globally; color-only error states; `pointer-events: none` on interactive-looking elements.
    • Always: `:focus-visible`; text spacing overrides (1.4.12) respected; motion preferences honored.

    Performance considerations

    Reduced motion and containment can improve perf — `prefers-reduced-motion` often correlates with users on low-end devices. Avoid expensive blur on focus rings; use solid outline.

    • CLS: Focus ring outline-offset shouldn't shift layout — use outline not border width change.

    SEO considerations

    Overlap: Readable contrast and reflow improve mobile usability scores in Lighthouse — a ranking signal via Core Web Vitals adjacent checks.

    • Tap targets: Google mobile-friendly audit aligns with WCAG target size guidance.

    Scalability considerations

    Multi-brand tokens: Each white-label theme must re-validate contrast pairs — automated diff on token export prevents one tenant shipping 3.8:1 gray-on-gray.

    • Dark mode: Separate contrast matrix per theme — dark gray text on dark gray bg is a common regression.

    Common production issues

    Incidents: Global `outline: none` in CSS reset broke keyboard nav sitewide. Sticky promo banner covered focused checkout field — 2.4.11 failure. Animation ignored `prefers-reduced-motion` — vestibular disorder complaints.

    • Fix pattern: Reset `:focus-visible` in design system base layer; never in product overrides.

    Debugging guide

    Debug WCAG CSS failures: Chrome DevTools → Rendering → Emulate forced colors; Accessibility pane shows contrast ratio; axe DevTools lists criterion IDs.

    • Zoom test: 200% browser zoom + 320px viewport — horizontal scroll indicates 1.4.10 fail.
    • Focus test: Tab through page recording video — verify ring visible on every interactive element.

    Best practices

    • Encode WCAG requirements as design tokens — focus, contrast, target size, motion.
    • Use :focus-visible, not :focus, for pointer vs keyboard differentiation.
    • Test forced-colors and prefers-reduced-motion in CI story snapshots.
    • Document WCAG criterion ID per component in design system docs.
    • Block PR merge on critical axe color-contrast and target-size violations.

    Anti-patterns

    • outline: none on * { } reset without :focus-visible replacement.
    • Using only :hover styles for critical state — no :focus or aria state styling.
    • Fixed font-size px preventing user text resize (1.4.4).
    • position:fixed cookie banners covering focused elements without scroll-margin.

    Trade-offs

    • Benefit: Tokenized WCAG CSS prevents audit fire drills before launch.
    • Benefit: Legal defensibility with automated + manual test artifacts.
    • Cost: Stricter palette reduces designer freedom — governance required.
    • Cost: 44px targets increase density trade-offs on mobile toolbars.
    • Risk if skipped: Retrofit cost 10× vs building tokens from sprint one.

    Architecture review questions

    • Does every interactive component have visible :focus-visible styles?
    • Are all text/UI contrast pairs validated at AA in both light and dark themes?
    • Does 200% zoom reflow without two-axis scrolling on primary flows?
    • Are animations gated behind prefers-reduced-motion?
    • Do sticky/fixed elements obscure focused controls (2.4.11)?

    Interview questions

    Which WCAG 2.2 criteria are primarily CSS-owned?(Advanced)

    Contrast (1.4.3/11), resize/reflow (1.4.4/10), focus visible (2.4.7), focus not obscured (2.4.11/12), target size (2.5.8), reduced motion (2.3.3). HTML owns semantics; CSS owns visual operability and perceivability.

    Follow-up: How do you enforce contrast at scale?

    Why is outline:none dangerous and what's the fix?(Intermediate)

    It removes the native focus indicator keyboard users require (2.4.7). Fix: never global none; use :focus-visible with high-contrast outline/box-shadow token; ensure 3:1 contrast against adjacent colors.

    Follow-up: Does box-shadow focus ring affect layout?

    Explain focus not obscured in a modal with sticky header.(Advanced)

    When focus moves to a control near the top of the modal, sticky site header must not cover it. Use scroll-margin on :focus-visible, raise modal z-index above chrome, or shrink sticky header when dialog open via :has(.dialog[open]).

    Follow-up: 2.4.11 vs 2.4.12 difference?

    Hands-on exercise

    Exercise: Audit a button component CSS against WCAG 2.2 AA — add :focus-visible token, 44px min target, forced-colors border, reduced-motion transition off. Pass axe zero critical on three themes.

    • Document criterion ID per CSS change in PR.
    • Record keyboard tab video through component states.

    Staff engineer notes

    • WCAG 2.2 AA is the enterprise default — map criteria to tokens, not wiki pages.
    • Forced-colors mode breaks gradient buttons — always provide border fallback.
    • Legal cares about test evidence — axe JSON artifacts per release, not screenshots alone.

    Common pitfalls

    • Assuming Safari :focus-visible matches Chrome without device testing.
    • Checking contrast only on primary button — missing disabled/placeholder states.
    • Using vw-only typography that fails 200% zoom combined with browser text sizing.

    Try it yourself

    Edit the CSS panel — the preview updates live. Use DevTools Performance and Accessibility panels to validate.

    Try it yourself

    Preview

    Summary

    WCAG 2.2 CSS conformance encodes accessibility requirements in design tokens and component styles — focus visibility, contrast, target size, motion, and reflow — enforced by axe/Lighthouse in CI and validated with keyboard and screen reader testing.

    Key takeaways

    • WCAG 2.2 AA maps directly to CSS tokens: focus, contrast, target size, motion, reflow.
    • Use :focus-visible and prefers-reduced-motion — never global outline removal.
    • Automate with axe; validate zoom, forced-colors, and keyboard manually.
    Ready to mark this lesson complete?Track your journey across the entire course.