Text you draw with the tokens passes WCAG AA on the page and card backgrounds, in both modes and every hue. Four things stay yours to check: text on the third background, control borders, meaning shown by hue alone, and Increase Contrast.
let theme = Color.proOrange // Lisbon
VStack(alignment: .leading, spacing: 4) {
Text("Lisbon")
.font(.headline)
.foregroundStyle(theme.foregroundPrimary)
Text("3 nights from October 12")
.font(.subheadline)
.foregroundStyle(theme.foregroundSecondary)
Text("€480")
.font(.subheadline)
.foregroundStyle(theme.foregroundTertiary) // _700 in light mode, _300 in dark
}
.padding()
.background(theme.backgroundPrimary) // _50 in light mode, _1000 in darkThe faintest line, the price in light mode, measures 6.10:1. AA asks 4.5:1 for body text.
What's guaranteed#
The same ratio in every hue#
Color.proOrange._100.contrastRatio(to: Color.proOrange._700) // 5.53, Lisbon
Color.proPink._100.contrastRatio(to: Color.proPink._700) // 5.53, Kyoto
Color.proSky._100.contrastRatio(to: Color.proSky._700) // 5.53, ReykjavíkEvery hue has the same lightness at each stop, so a pair of stops measures the same in all 36 hues and in your brand's family, and theming keeps your contrast. Gray has its own ladder: 8.73:1 for this pair.
Stops far enough apart#
When you pick stops yourself, count the stops between text and background. 9 apart passes AA for large text and control borders, 12 for body text, and 14 passes AAA, in all 37 families and between them. The distance rule covers other uses.
On screens without Display P3#
These ratios are exact on Display P3 screens, which every iPhone since the iPhone 7 has. An sRGB-only screen, like many external monitors, clips the colors beyond sRGB and moves a few pairs slightly. The text tokens still pass AA, at 4.77:1 or more, and stops 12 apart still reach 4.5:1. Stops 9 apart can dip to 2.93:1, and white on _600 to 4.48:1 in mint, teal and turquoise.
What you still check#
Text on the tertiary background#
On backgroundTertiary, tertiary text falls under 4.5:1 in both modes, and secondary text does in dark mode. The lowest, 3.51:1, is enough only for large text, so use foregroundPrimary for body text there.
The app-wide gray tokens on Color pass there, at 5.24:1 or more. Inverted secondary and tertiary text fall short on invertedBackgroundTertiary too.
Borders of controls#
A border that shows where a control is, like these tags' edges, needs 3:1 under WCAG's non-text contrast rule. outlinePrimary reaches it on every background token, in every hue and both modes, at 3.08:1 or more, as in borders people need to see. outlineSecondary and outlineTertiary are faint on purpose, for dividers and card edges, which WCAG sets no minimum for.
APCA scores#
The ratios on this page are WCAG 2, the standard audits check. APCA, the candidate for WCAG 3, estimates luminance its own way, so its scores move up to Lc 1.2 between hues. contrastRatio(to:method:) measures both.
Meaning shown by hue alone#
Two families at the same stop differ only in hue. The second row is the pair as someone with deuteranopia, a red-green color blindness, sees it at full severity, and in grayscale the two are identical. So give color a second cue, as WCAG's use of color rule asks: a label, an icon, or a difference in lightness. Using tokens in charts shows how for data.
Increase Contrast#
The tokens follow light and dark mode, not the Increase Contrast setting. High contrast modes moves text and borders two stops further from the background when it's on.
Sources#
- W3C, WCAG 2.2: success criteria 1.4.1 (use of color), 1.4.3 and 1.4.6 (contrast) and 1.4.11 (non-text contrast).
- APCA, Bronze simple mode, for Lc levels.
- Gustavo Machado, Manuel Oliveira and Leandro Fernandes, A Physiologically-based Model for Simulation of Color Vision Deficiency, IEEE Transactions on Visualization and Computer Graphics, 2009, for the deuteranopia simulation.
- The library's ColorTokens.swift, for the stops behind each token.
See also
- Managing dark mode Get dark mode without extra code: tokens switch stops for you, and your own colors can too.
- Replacing your app colors Move backgrounds, text, outlines, states, gradients and charts to tokens, one screen at a time.
- How the ramps are built The lightness and chroma behind every stop, so any hue you pick gives the same contrast.
- What does equal lightness cost? What equal contrast costs, from quieter reds to olive yellows, and what you can do about each.