WCAG 2.3.3: Animation from Interactions

WCAG 2.3.3, Animation from Interactions, is a Level AAA success criterion introduced in WCAG 2.1. Its primary goal is to ensure that users have control over animations that are triggered by their interactions with a web page. Specifically, it mandates that web content provides a mechanism to disable or pause any non-essential animations that start as a result of user action, such as hovering, clicking, or focusing on an element.

This criterion helps to create a more inclusive web by accommodating users who may experience discomfort, distraction, or even physical symptoms like vestibular disorders or seizures due to animated content.

Understanding WCAG 2.3.3: Animation from Interactions

The web is increasingly dynamic, often using animations to enhance user experience, provide feedback, or simply add visual flair. While many animations are subtle and harmless, some can be problematic for certain users. WCAG 2.3.3 addresses animations that are:

  • Triggered by user interaction: This includes animations that start when a user hovers over an element, clicks a button, focuses on an input field, or scrolls the page.
  • Non-essential: The criterion applies specifically to animations that are purely decorative or aesthetic, and whose removal would not impede the functionality or understanding of the content.

For such animations, there must be a way for the user to turn them off. This can be through a site-specific setting, or by honoring system-level preferences.

Who Benefits from This Criterion?

Providing control over animations significantly benefits a wide range of users, including:

  • Users with Vestibular Disorders: Conditions like vertigo, Meniere’s disease, or inner ear disorders can be severely impacted by animated content, leading to nausea, dizziness, and disorientation. Rapid or unexpected movement can trigger these symptoms.
  • Users with Cognitive Disabilities: Individuals with ADHD, autism spectrum disorders, or other cognitive impairments may find animations distracting, making it difficult to concentrate on essential content or tasks.
  • Users Prone to Seizures: While WCAG 2.3.1 (Three Flashes or Below Threshold) addresses flashing content, some rapid, repetitive, or high-contrast animations could still pose a risk, especially for individuals with photosensitive epilepsy.
  • Users with Motion Sickness: Anyone susceptible to motion sickness, even without a diagnosed disorder, can experience discomfort from certain animations.
  • Users with Low Vision: Some animations, especially those involving small moving targets, can be difficult to track and interact with for users with low vision.
  • Users in Distracting Environments: Even without specific disabilities, users in busy or distracting environments may prefer to disable animations to improve focus and reduce cognitive load.

Official Requirements and Success Criteria

The exact wording of Success Criterion 2.3.3 Animation from Interactions (Level AAA) is:

Motion animation triggered by interaction can be disabled, unless the animation is essential to the functionality or the information being conveyed.

Key phrases within this criterion include:

  • "Motion animation triggered by interaction": Refers to animations that start or change state when a user performs an action (e.g., hover, click, focus, scroll).
  • "Can be disabled": There must be a user-accessible mechanism to turn off, pause, or stop the animation.
  • "Unless the animation is essential": This is a critical exception. An animation is considered essential if removing it would fundamentally alter or remove functionality or communication of information. For instance, an animation that shows the path of a drag-and-drop operation might be essential if the path itself is the primary way to understand the interaction. Most decorative animations, however, are not essential.

Practical Guidelines for Compliance

Achieving compliance with WCAG 2.3.3 involves thoughtful design and implementation strategies:

1. Provide a Mechanism to Disable Animations

The most direct way to comply is to offer a user interface control that toggles animations on or off. This control should be easily discoverable and persistent across sessions.

2. Respect System-Wide Preferences

Modern operating systems and browsers offer accessibility settings, such as "Reduce motion." Web content should ideally respect these preferences using CSS media queries (@media (prefers-reduced-motion: reduce)). This is often the most elegant and user-friendly solution, as it allows users to set their preference once at the OS level.

3. Distinguish Essential from Non-Essential Animations

Carefully evaluate each animation:

  • Essential: If the animation’s movement is the only way to understand a process, outcome, or spatial relationship that is critical to the task, it might be essential. Examples are rare but could include a visualizer showing real-time data flow or an animation that must occur to demonstrate a specific physical interaction.
  • Non-essential: Most animations fall into this category: decorative hover effects, parallax scrolling, elements sliding into view, expanding menus (if a static open/close is also available), hero image carousels, or "delightful" micro-interactions. These should be able to be disabled.

4. Default State Consideration

For highly intense or potentially problematic animations, consider making them opt-in rather than opt-out. By default, animations could be off, requiring users to explicitly enable them if they wish.

Examples of Implementation

Correct Implementations

Example 1: Using prefers-reduced-motion Media Query

This is the most common and recommended approach, automatically adapting to user’s system-wide settings.

/* Default CSS for an element with animation */
.animated-button {
  transition: transform 0.3s ease-out;
}

.animated-button:hover {
  transform: translateY(-5px) scale(1.05);
  box-shadow: 0 4px 8px rgba(0, 0, 0, 0.2);
}

/* Override animations if user prefers reduced motion */
@media (prefers-reduced-motion: reduce) {
  .animated-button {
    transition: none;
    animation: none;
    transform: none !important; /* Ensure no residual transform */
    box-shadow: none !important;
  }
  .animated-button:hover {
    /* No animation on hover, but still show visual change if desired (e.g., background-color) */
    background-color: #f0f0f0;
  }
}

Explanation: The element animates on hover by default. However, if the user has enabled "Reduce motion" in their operating system settings, the @media (prefers-reduced-motion: reduce) block will apply, disabling all motion transitions and animations for that element. This provides a robust, system-wide solution.

Example 2: User-Controlled Toggle for Site-Specific Animations

For scenarios where you need more granular control or want to provide a site-specific override, a UI toggle can be implemented.

<div class="settings-panel">
  <label for="animation-toggle">
    <input type="checkbox" id="animation-toggle" aria-describedby="animation-toggle-desc" checked>
    <span>Enable Site Animations</span>
  </label>
  <p id="animation-toggle-desc" class="sr-only">Turns off decorative animations on this website.</p>
</div>

<!-- Example animated element -->
<div class="card animated-slide-in">Card Content</div>
/* Default animation for elements */
.animated-slide-in {
  opacity: 0;
  transform: translateY(20px);
  transition: opacity 0.5s ease-out, transform 0.5s ease-out;
}

.card.visible {
  opacity: 1;
  transform: translateY(0);
}

/* Class to disable animations */
body.animations-disabled .animated-slide-in {
  transition: none !important;
  animation: none !important;
  transform: none !important;
  opacity: 1 !important; /* Ensure it's visible when animations are off */
}
const animationToggle = document.getElementById('animation-toggle');
const body = document.body;

// Function to apply/remove 'animations-disabled' class
function toggleAnimations(enable) {
  if (!enable) {
    body.classList.add('animations-disabled');
    localStorage.setItem('siteAnimations', 'disabled');
  } else {
    body.classList.remove('animations-disabled');
    localStorage.setItem('siteAnimations', 'enabled');
  }
}

// 1. Check system preference on load
const prefersReducedMotion = window.matchMedia('(prefers-reduced-motion: reduce)').matches;
if (prefersReducedMotion) {
  animationToggle.checked = false;
  toggleAnimations(false);
}

// 2. Override with local storage preference if available
const storedPreference = localStorage.getItem('siteAnimations');
if (storedPreference === 'disabled') {
  animationToggle.checked = false;
  toggleAnimations(false);
} else if (storedPreference === 'enabled') {
  animationToggle.checked = true;
  toggleAnimations(true);
}

// 3. Listen for user toggle interaction
animationToggle.addEventListener('change', function() {
  toggleAnimations(this.checked);
});

// For demonstration: make cards visible after a delay or on scroll
window.addEventListener('load', () => {
  document.querySelectorAll('.animated-slide-in').forEach(card => {
    // In a real app, this would be triggered by scroll observer or specific event
    if (!body.classList.contains('animations-disabled')) {
        setTimeout(() => card.classList.add('visible'), 100); // Simulate animation trigger
    } else {
        card.classList.add('visible'); // Immediately visible if animations are off
    }
  });
});

Explanation: This setup provides a checkbox that, when unchecked, adds a class to the <body> element. This class then uses CSS to disable or remove animations. It also respects prefers-reduced-motion and persists the user’s choice using localStorage.

Incorrect Implementations

Example 1: Uncontrollable Hover Animation

A purely decorative element that animates on hover with no way to disable it.

.product-thumbnail {
  transition: transform 0.2s ease-in-out;
}

.product-thumbnail:hover {
  transform: scale(1.1) rotate(5deg);
}

Reason for incorrectness: This animation is triggered by user interaction (hover) and is purely decorative. There is no mechanism provided for the user to disable this animation, making it problematic for users sensitive to motion.

Example 2: Auto-Advancing Carousel with No Pause/Stop

A carousel or slider that automatically transitions between slides (even if triggered initially by a click/load) and offers no controls to pause or stop its motion.

<div class="image-carousel">
  <img src="img1.jpg" class="active" alt="Description 1">
  <img src="img2.jpg" alt="Description 2">
  <!-- ... more images -->
</div>
.image-carousel img {
  /* ... styling ... */
}
.image-carousel .active {
  animation: slide-transition 10s infinite linear; /* Continuous animation */
}

@keyframes slide-transition {
  0%   { opacity: 0; transform: translateX(100%); }
  10%  { opacity: 1; transform: translateX(0); }
  90%  { opacity: 1; transform: translateX(0); }
  100% { opacity: 0; transform: translateX(-100%); }
}

Reason for incorrectness: Although the carousel might load on page load (not strictly an "interaction" trigger in some contexts), if it has interactive elements to navigate, and the animation for advancing cannot be controlled (paused/stopped/disabled) by the user, it violates the spirit of this criterion, especially if the movement is significant. The intent is to provide control over all non-essential motion triggered by or present during interaction.

Best Practices and Common Pitfalls

Best Practices

  • Prioritize prefers-reduced-motion: Always design with the @media (prefers-reduced-motion: reduce) media query in mind. It’s the most inclusive approach as it leverages existing user preferences.
  • Offer Clear UI Controls: If a site-specific toggle is provided, ensure it’s easily discoverable (e.g., in a settings menu or accessibility widget), clearly labeled, and its state is persistent.
  • Degrade Gracefully: When animations are disabled, ensure the content still conveys all necessary information and functionality through static states, fades, or other non-motion cues.
  • Test Thoroughly: Always test your site with animations disabled (both via OS settings and any site-specific toggles) to ensure no critical functionality is lost or becomes unclear.
  • Consider Minimal Animations by Default: For new designs, consider starting with minimal motion and only adding more complex animations where they genuinely enhance the user experience for a broad audience, and always provide a way to disable them.

Common Pitfalls

  • Ignoring `prefers-reduced-motion`: Relying solely on a site-specific toggle, or worse, providing no control at all, is a common pitfall. The media query is a powerful tool for accessibility.
  • Making Animations Essential: Designing an interaction where the animation itself is the only way to understand how something works or what information is conveyed. This is generally poor design and should be avoided.
  • Inconsistent Behavior: Some animations are disabled, but others are not, leading to a confusing and frustrating experience for users trying to control motion.
  • Lack of Persistence: User animation preferences are forgotten after a page refresh or new session, forcing them to reset their choices repeatedly.
  • Accessibility of Controls: Ensuring the animation toggle itself is accessible (keyboard navigable, screen reader friendly) is just as important as the animations it controls.

Key Takeaways

  • WCAG 2.3.3 requires user control over non-essential, interaction-triggered motion animations.
  • The @media (prefers-reduced-motion: reduce) CSS media query is your primary tool for compliance.
  • Always distinguish between essential (rare) and non-essential (most) animations.
  • Provide clear, persistent, and accessible mechanisms for users to manage their animation preferences.

Further Reading

Privacy Overview

This website uses cookies so that we can provide you with the best user experience possible. Cookie information is stored in your browser and performs functions such as recognising you when you return to our website and helping our team to understand which sections of the website you find most interesting and useful.