How do you respect Reduce Motion, Increase Contrast, Bold Text, Reduce Transparency, Differentiate Without Color and Smart Invert?

24.2.2 · L3 · Interview

Predict first

In a plain process, what do the display-setting flags report, and can invert-colour avoidance be set on a view?

import UIKit

@MainActor func run() {
    print(UIAccessibility.isReduceMotionEnabled, UIAccessibility.isBoldTextEnabled, UIAccessibility.isDarkerSystemColorsEnabled,
          UIAccessibility.isReduceTransparencyEnabled, UIAccessibility.isInvertColorsEnabled, UIAccessibility.shouldDifferentiateWithoutColor)
    let photo = UIImageView()
    photo.accessibilityIgnoresInvertColors = true
    print(photo.accessibilityIgnoresInvertColors)
}
MainActor.assumeIsolated { run() }
  • six false values, then true
  • six true values, then false
  • It crashes outside Settings

Predict first

Does a SwiftUI view that reads Reduce Motion, Differentiate Without Color, contrast and Reduce Transparency compile?

import SwiftUI

struct Pulse: View {
    @Environment(\.accessibilityReduceMotion) var reduceMotion
    @Environment(\.accessibilityDifferentiateWithoutColor) var noColorOnly
    @Environment(\.colorSchemeContrast) var contrast
    @Environment(\.accessibilityReduceTransparency) var reduceTransparency
    @State private var on = false
    var body: some View {
        Circle()
            .fill(contrast == .increased ? Color.black : Color.blue)
            .overlay { if noColorOnly { Image(systemName: "checkmark") } }
            .scaleEffect(on && !reduceMotion ? 1.2 : 1)
            .animation(reduceMotion ? nil : .easeInOut, value: on)
    }
}
  • Yes
  • No, these settings are UIKit only

Mental model. A good thermostat does not insist on 21 degrees. It reads the person’s preference and adjusts. These settings are the person’s preferences for how the screen should behave.

Users can change how the system looks and moves, and your app should follow without being asked. Reduce Motion (UIAccessibility.isReduceMotionEnabled, SwiftUI \.accessibilityReduceMotion) is for people who get dizzy or nauseous from large movement: replace parallax, zooms, spinning and bouncing with a fade or an instant change, and avoid auto-playing animation. Increase Contrast (isDarkerSystemColorsEnabled, \.colorSchemeContrast) asks for stronger borders and colours: provide high-contrast variants of your custom colours in the asset catalog. Bold Text (isBoldTextEnabled) and Button Shapes make text heavier and controls obvious. Reduce Transparency (isReduceTransparencyEnabled) replaces blur and translucency with solid colour. Differentiate Without Color (shouldDifferentiateWithoutColor, \.accessibilityDifferentiateWithoutColor) says not to rely on colour alone: add a shape, icon or text (an error state with a red outline and an icon). Smart Invert inverts the interface, so mark images, video and anything that must keep its colours with accessibilityIgnoresInvertColors = true (.accessibilityIgnoresInvertColors()), as the check below does. All of these are plain properties and environment values you can read, and notifications (for example UIAccessibility.reduceMotionStatusDidChangeNotification) tell you when they change.

Use the system components and semantic colours wherever possible, because they adapt for free: system colours have high-contrast variants, standard controls honour Bold Text, and system materials respond to Reduce Transparency. Custom drawing, custom animations and hard-coded colours are where you must add the support yourself. Test each setting on the device (Settings ▸ Accessibility ▸ Display & Text Size and Motion) and with the Accessibility Inspector’s settings simulation, and treat Dark Mode as a sibling feature: colours defined once in the asset catalog with light, dark and high-contrast variants cover all three. Never read these settings once and cache them, since users change them while the app runs.

The flags reflect system settings, which are off here; the ignore-invert flag is a per-view property you can set.

Each setting has a SwiftUI environment value.

Common traps

  • Animating the same way regardless of Reduce Motion. For some users large motion makes the app unusable.
  • Marking an error only with a red colour. People with colour blindness cannot see it; add an icon or text.

They might follow up with

  • What do you do with photos under Smart Invert? Mark them to ignore inversion so they keep their colours.
  • How do you know when a setting changes? Observe the matching status-change notification, or read the SwiftUI environment value.

Related questions

  • 24.2.1 How does Dynamic Type work, how do you support it in UIKit and SwiftUI, and how do layouts adapt at…
  • 24.2.3 What contrast ratio and touch-target size should you meet, and how do you design for colour blindness?
  • 24.5.1 How do you test accessibility: the Accessibility Inspector, automated audits in XCUITest, identifiers versus…
  • 8.7.1 What is the difference between implicit and explicit animation, and how do transitions fit in?

← How does Dynamic Type work, how do you support it in UIKit and…   What contrast ratio and touch-target size should you meet, and how do… →