Color & Contrast Guidance
Airframe ships with a default color palette that meets WCAG 2.2 AA contrast requirements. When overriding tokens, you must ensure contrast ratios are maintained.
WCAG 2.2 AA Contrast Requirements
Section titled “WCAG 2.2 AA Contrast Requirements”- Normal text (smaller than 18pt/24px): 4.5:1 minimum
- Large text (18pt/24px or larger, or 14pt/19px bold): 3:1 minimum
- UI components (icons, borders): 3:1 minimum
- Focus indicators: Must have 3:1 contrast with adjacent colors
Default Token System
Section titled “Default Token System”Airframe uses semantic color tokens:
/* Semantic tokens (contrast-safe by default) */
--af-color-text /* Meets 4.5:1 on --af-color-background */
--af-color-text-muted /* Meets 3:1 on --af-color-background */
--af-color-background /* Base background */
--af-color-surface-primary /* Primary surface background */
--af-color-border /* Border color */
--af-color-primary /* Primary action color */
--af-color-on-primary /* Text on primary (meets contrast) */Overriding Tokens Safely
Section titled “Overriding Tokens Safely”✅ Safe: Override with Contrast-Checked Colors
Section titled “✅ Safe: Override with Contrast-Checked Colors”:root {
/* ✅ Good - verify contrast before using */
--af-base-primary: #018183; /* Checked: 4.5:1 on white */
--af-color-primary: var(--af-base-primary);
}❌ Unsafe: Override Without Checking
Section titled “❌ Unsafe: Override Without Checking”:root {
/* ❌ Bad - may not meet contrast */
--af-color-text: #CCCCCC; /* Too light on white */
}Checking Contrast
Section titled “Checking Contrast”Use Accessibility Contrast Checker
Section titled “Use Accessibility Contrast Checker”- Visit our Accessibility Contrast Checker
- Enter your foreground and background colors
- Verify ratio meets requirements:
- Normal text: 4.5:1 or higher
- Large text: 3:1 or higher
Use Browser DevTools
Section titled “Use Browser DevTools”Chrome DevTools:
- Inspect element
- Click color swatch in Styles panel
- Contrast ratio shown automatically
Firefox DevTools:
- Inspect element
- Click color in Computed panel
- Contrast ratio shown in color picker
Hover States
Section titled “Hover States”Hover states must not reduce contrast below requirements:
/* ✅ Good - hover maintains or improves contrast */
.af-btn:hover {
background: color-mix(in srgb, var(--af-color-primary), black 10%);
}
/_ ❌ Bad - hover reduces contrast _/
.af-btn:hover {
background: color-mix(in srgb, var(--af-color-primary), white 30%);
/_ May reduce contrast below 4.5:1 _/
}Color-Only Information
Section titled “Color-Only Information”Never rely on color alone to convey information:
<!-- ❌ Bad - error only shown by color -->
<input style="border-color: red;">
<!-- ✅ Good - error shown multiple ways -->
<input
aria-invalid="true"
aria-describedby="error"
class="af-input af-is-error"
>
<div id="error">
Error message
</div>Required indicators:
<!-- ❌ Bad - required only shown by red asterisk -->
<label for="name">
Name
<span style="color: red;">
*
</span>
</label>
<input id="name" class="af-input" type="text" required>
<!-- ✅ Good - required shown with text -->
<label for="name">
Name
<span class="af-text-muted">
(required)
</span>
</label>
<input id="name" class="af-input" type="text" required>Focus Indicators
Section titled “Focus Indicators”Focus rings must have sufficient contrast:
/* ✅ Good - focus ring has 3:1 contrast */
:focus-visible {
outline: 2px solid var(--af-color-primary);
outline-offset: 2px;
}
/_ ❌ Bad - focus ring too subtle _/
:focus-visible {
outline: 1px solid rgba(0, 0, 0, 0.2);
/_ May not meet 3:1 contrast _/
}Airframe provides focus ring tokens that meet contrast:
--af-focus-ring-width: 2px;
--af-focus-ring-color: /* Meets 3:1 contrast */
--af-focus-ring-offset: 2px;Dark Mode
Section titled “Dark Mode”When implementing dark mode, verify contrast for both themes:
/* Light theme */
[data-theme="light"] {
--af-color-text: #1f2937;
--af-color-background: #ffffff;
/* 4.5:1 contrast ✅ */
}
/_ Dark theme _/
[data-theme="dark"],
.dark {
--af-color-text: #f9fafb;
--af-color-background: #111827;
/_ 4.5:1 contrast ✅ _/
}Semantic Color Tokens
Section titled “Semantic Color Tokens”Use semantic tokens instead of raw colors:
/* ✅ Good - uses semantic token */
.error-message {
color: var(--af-color-danger);
}
/_ ❌ Bad - uses raw color _/
.error-message {
color: #dc2626;
/_ What if theme changes? _/
}Testing Contrast
Section titled “Testing Contrast”Automated Tools
Section titled “Automated Tools”- axe DevTools - Checks contrast automatically
- Lighthouse - Includes contrast audit
- WAVE - Web accessibility evaluation tool
Manual Testing
Section titled “Manual Testing”- Use contrast checker - Verify all text meets requirements
- Test hover states - Ensure contrast doesn’t drop
- Test focus indicators - Verify 3:1 contrast
- Test in dark mode - If you support it
- Test with color blindness simulators - Ensure information isn’t color-only
Common Mistakes
Section titled “Common Mistakes”❌ Too Light Text
Section titled “❌ Too Light Text”/* ❌ Bad - doesn't meet 4.5:1 */
--af-color-text: #CCCCCC;❌ Hover Reduces Contrast
Section titled “❌ Hover Reduces Contrast”/* ❌ Bad - hover makes text harder to read */
.button:hover {
color: color-mix(in srgb, currentColor, white 40%);
}❌ Color-Only Errors
Section titled “❌ Color-Only Errors”<!-- ❌ Bad - error only by color -->
<input style="border-color: red;">❌ Insufficient Focus Contrast
Section titled “❌ Insufficient Focus Contrast”/* ❌ Bad - focus ring too subtle */
:focus-visible {
outline: 1px solid rgba(0, 0, 0, 0.1);
}Best Practices
Section titled “Best Practices”- Always check contrast before overriding tokens
- Use semantic tokens instead of raw colors
- Test hover states to ensure contrast doesn’t drop
- Never rely on color alone to convey information
- Verify focus indicators have sufficient contrast
- Test in both light and dark modes if supported
- Use automated tools to catch contrast issues early