Skip to main content
    Back to blog
    DevelopmentPublished on October 18, 2026

    Contrast, Motion and Button Size: Visual Accessibility

    Contrast requirements, information beyond color, high contrast mode, prefers-reduced-motion, target sizes and zoom

    Contrast, Motion and Button Size: Visual Accessibility

    Part 5 of 8 in the "Accessible Web in Practice" series. Previous part: Keyboard and Focus: Building a Website You Can Use Without a Mouse.

    Low text contrast is the most common accessibility problem on the web: it appears on 83.9% of popular websites. This part covers everything visual — contrast and color, display modes, animation, target size and zoom.

    Color, contrast and display modes

    Contrast requirements

    What Minimum (AA) Criterion
    Normal text 4.5 : 1 1.4.3
    Large text (24px and up, or about 18.7px bold) 3 : 1 1.4.3
    UI components: input borders, icons, focus indicators, states 3 : 1 1.4.11
    Meaningful graphics (chart lines, pie segments) 3 : 1 1.4.11

    The requirement doesn't apply to disabled controls, logos or purely decorative elements.

    Typical problems:

    • light gray #999 text on white: only about 2.8 : 1;
    • placeholders and hints that are too faint;
    • white text on a bright brand color;
    • text over a photo with no backing;
    • a #ddd input border on white — the field is "invisible" to low-vision users.

    You can check contrast right in DevTools: in Chrome, the color picker in the Styles panel shows the contrast ratio with AA/AAA marks. There are standalone tools too, such as the WebAIM Contrast Checker.

    If colors live in a design system, define background/text pairs that pass contrast up front and disallow the rest.

    Not by color alone

    Criterion 1.4.1: color must not be the only way to convey information. About 8% of men have some form of color vision deficiency, and in bright sun or on a poor monitor everyone distinguishes colors worse.

    <!-- ❌ Error shown only by a red border -->
    <input class="border-red">
    
    <!-- ✅ Color + icon + text -->
    <input aria-invalid="true" aria-describedby="err">
    <p id="err" class="error"><svg aria-hidden="true">...</svg> Choose a date in the future</p>
    

    Same with links in body text: if a link differs from surrounding text only by color, the contrast between them must be at least 3 : 1, plus an extra cue on hover and focus. The simplest option is to keep the underline.

    /* Links in article text keep their underline */
    .prose a {
      text-decoration: underline;
      text-underline-offset: 0.15em;
    }
    

    In charts, distinguish lines by more than color: markers, patterns or labels placed right at the lines.

    High contrast mode and dark theme

    Windows has contrast themes (forced colors mode): the browser replaces all colors with the user's system palette. What breaks:

    @media (forced-colors: active) {
      .icon {
        /* SVG using currentColor adapts on its own; for masks use a system color */
        background-color: CanvasText;
      }
      .card {
        border: 1px solid CanvasText; /* instead of a shadow */
      }
    }
    

    You can test it in Chrome DevTools: Rendering → Emulate CSS media feature forced-colors.

    A dark theme via prefers-color-scheme needs its own contrast check too — its color pairs are different.

    Motion and animation

    Parallax, zoom-on-scroll and large screen movements can cause dizziness and nausea in people with vestibular disorders. For people with ADHD, endless animation makes reading harder. Operating systems have a "Reduce motion" setting, and browsers expose it through the prefers-reduced-motion media query.

    /* Basic approach: enable animation only for those who haven't asked to reduce it */
    @media (prefers-reduced-motion: no-preference) {
      .hero {
        animation: slide-in 0.6s ease-out;
      }
      html {
        scroll-behavior: smooth;
      }
    }
    

    Or the reverse — a global safety net:

    @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;
      }
    }
    

    In JavaScript (for animation libraries, for example):

    const reduceMotion = window.matchMedia('(prefers-reduced-motion: reduce)').matches;
    
    element.animate(
      [{ transform: 'translateY(20px)', opacity: 0 }, { transform: 'none', opacity: 1 }],
      { duration: reduceMotion ? 0 : 400, easing: 'ease-out', fill: 'forwards' }
    );
    

    "Reduce motion" doesn't mean "remove everything": a gentle fade is usually fine. Movement, scaling and rotation are what cause problems.

    Two more rules:

    • Anything that moves for more than 5 seconds (carousels, tickers, background video) needs a pause button (criterion 2.2.2).
    • Nothing flashes more than three times per second (2.3.1) — it can trigger seizures.

    Target size, gestures and zoom

    Target size

    WCAG 2.2 criterion 2.5.8 (level AA): an interactive target must be at least 24×24 CSS pixels, or a small target needs enough clear space that a 24px-diameter circle centered on it doesn't overlap neighboring targets. For mobile interfaces, platform guidelines are a better benchmark: Apple recommends 44×44 pt, Material Design 48×48 dp. WCAG level AAA (2.5.5) asks for 44×44 CSS pixels.

    You can enlarge the hit area without changing the look:

    /* 16px icon, 44px clickable area */
    .icon-button {
      display: inline-grid;
      place-items: center;
      min-width: 44px;
      min-height: 44px;
      padding: 0;
    }
    
    /* Or extend the hit area with a pseudo-element */
    .small-link {
      position: relative;
    }
    .small-link::after {
      content: "";
      position: absolute;
      inset: -10px;
    }
    

    Gestures and dragging

    • Complex gestures (pinch, two-finger swipe, drawing a path) need a single-tap alternative (2.5.1). If a map zooms with a pinch, it needs "+" and "−" buttons.
    • Dragging (2.5.7, new in 2.2): drag-and-drop list sorting, sliders, drag-to-upload — all need an alternative. For sorting, "Move up" / "Move down" buttons or a "Move to" menu; for uploads, a regular file picker button.
    • Activation on release (2.5.2): the action happens on release (click, pointerup), not on press (pointerdown), so people can "change their mind" by sliding their finger away.

    Zoom and reflow

    • Don't disable zoom:

      <!-- ❌ -->
      <meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no">
      
      <!-- ✅ -->
      <meta name="viewport" content="width=device-width, initial-scale=1">
      
    • Reflow (1.4.10): at a width of 320 CSS pixels (that's 400% zoom on a 1280px screen), content must be readable without horizontal scrolling. Responsive layouts usually handle this — check by narrowing the window or zooming in.

    • Font sizes in rem, not px, so the browser's font size setting is respected.

    • Text spacing (1.4.12): the layout must not break if the user increases line height to 1.5, letter spacing to 0.12em and word spacing to 0.16em. The main enemy is fixed-height blocks (height: 40px) instead of min-height.

    The "Accessible Web in Practice" series

    1. Web Accessibility: Who It Really Serves and Where to Start
    2. Semantic HTML and Alt Text: The Foundation of an Accessible Website
    3. Accessible Forms: Labels, Hints, Errors and Autofill
    4. Keyboard and Focus: Building a Website You Can Use Without a Mouse
    5. Contrast, Motion and Button Size: Visual Accessibility — you are here
    6. ARIA and Dynamic Content: When Attributes Help and When They Hurt
    7. Accessibility in React: IDs, Focus on Route Change and Announcements
    8. How to Test Accessibility: Automation, Manual Checks and a Checklist

    Next part: ARIA and Dynamic Content: When Attributes Help and When They Hurt

    Agama Labs builds websites and web applications. Want to check how accessible your site is? Write to us: hello@agamalabs.com

    Contact

    Let’s talk about your project

    Leave your details and we’ll get back to you within 2 business hours for a free consultation. Tell us what you’re building - we’ll help you choose the right approach.

    Business hours

    Mon–Fri: 08:00 AM – 5:00 PM (PST)
    Sat–Sun: Closed

    Request a call

    Fill out the form and we’ll reach out shortly

    By clicking the button, you agree to our Privacy Policy

    We value your privacy

    We use analytics cookies, including third-party ones, to see how the site is used and improve it