Case Study: Fixing Problematic Contrast with @weable/a11y-color-utils
7/27/2025
Case Study: Fixing Problematic Contrast with @weable/a11y-color-utils
Ensuring accessible color contrast is non-negotiable, but sometimes subtle issues slip through. This case study demonstrates how @weable/a11y-color-utils can help identify and fix contrast problems, using both WCAG 2.x and APCA metrics for a comprehensive solution.
The Scenario: Subtle Text Troubles
Imagine a web application dashboard with standard white (#FFFFFF) backgrounds. The design system defines several text colors:
primaryText:#212121(Very Dark Gray)secondaryText:#757575(Medium Gray)disabledText:#BDBDBD(Light Gray)accentText:#3498DB(Blue)
During user testing, some users reported difficulty reading the secondaryText used for captions and less important labels, especially on certain monitors. An automated WCAG check was run, but it didn't initially flag a major issue.
Initial Check with @weable/a11y-color-utils
Let's use the library to get the baseline contrast values for the secondaryText (#757575) against the white background (#FFFFFF).
import {
getColorContrast,
getColorContrastAPCA,
hexToRgb
} from '@weable/a11y-color-utils';
const secondaryText = hexToRgb('#757575');
const background = hexToRgb('#FFFFFF');
if (secondaryText && background) {
const wcagRatio = getColorContrast(secondaryText, background);
const apcaLc = getColorContrastAPCA(secondaryText, background);
console.log(`Secondary Text (#757575) vs White (#FFFFFF):`);
console.log(` - WCAG Contrast Ratio: ${wcagRatio.toFixed(2)}:1`);
// Output: WCAG Contrast Ratio: 4.63:1
console.log(` - APCA Lightness Contrast (Lc): ${apcaLc.toFixed(1)}`);
// Output: APCA Lightness Contrast (Lc): -61.6
}
Analysis:
- WCAG: The ratio is 4.63:1. This technically passes the WCAG 2.x AA requirement (>= 4.5:1) for normal text. This is why a basic automated check might not have flagged it as critical.
- APCA: The absolute Lc value is 61.6. Referring back to the APCA interpretation guide, an Lc of ~60 is often borderline or insufficient for standard body text sizes (e.g., 14-16px at 400 weight), which typically require Lc 75+ for comfortable reading.
This discrepancy highlights the value of APCA. While technically compliant with WCAG AA, the APCA score suggests the perceived contrast is low for typical body text usage, matching the user feedback.
Finding a Better Solution
Our goal is to find a slightly darker gray for secondaryText that:
- Comfortably passes WCAG AA (ideally with more headroom).
- Significantly improves the APCA Lc value towards the Lc 75 target for body text.
- Still feels visually distinct from
primaryText(#212121).
Let's try a darker gray, perhaps #616161.
// ... (import statements) ...
const newSecondaryText = hexToRgb('#616161');
const background = hexToRgb('#FFFFFF');
if (newSecondaryText && background) {
const wcagRatio = getColorContrast(newSecondaryText, background);
const apcaLc = getColorContrastAPCA(newSecondaryText, background);
console.log(`\nNew Secondary Text (#616161) vs White (#FFFFFF):`);
console.log(` - WCAG Contrast Ratio: ${wcagRatio.toFixed(2)}:1`);
// Output: WCAG Contrast Ratio: 6.44:1
console.log(` - APCA Lightness Contrast (Lc): ${apcaLc.toFixed(1)}`);
// Output: APCA Lightness Contrast (Lc): -72.3
}
Analysis of #616161:
- WCAG: 6.44:1 – Comfortably exceeds the AA threshold of 4.5:1 and approaches the AAA threshold of 7:1.
- APCA: Lc 72.3 – A significant improvement! This is much closer to the ideal Lc 75+ range for body text, indicating substantially better perceptual contrast than the original
#757575. - Visual:
#616161is noticeably darker than#757575but still lighter than#212121, maintaining the visual hierarchy.
Implementing the Fix
Based on these results, the design system was updated:
- The
secondaryTextcolor was changed from#757575to#616161. - Automated tests (similar to those in the CI/CD tutorial) were updated to check this new color pair against both WCAG (>= 4.5) and APCA (>= Lc 70 or 75, depending on exact usage) thresholds.
Conclusion
This case study illustrates several key points:
- WCAG AA is a Minimum: Relying solely on the bare minimum WCAG AA pass/fail can sometimes miss real-world readability issues.
- APCA Provides Deeper Insight: APCA's perceptually-based Lc values can flag combinations that, while technically compliant, might still be difficult for users to read, especially for body text.
- Use Both Metrics: Using
getColorContrast(WCAG) for compliance andgetColorContrastAPCAfor perceptual assessment provides a more complete picture of accessibility. - Iterative Improvement: Libraries like
@weable/a11y-color-utilsmake it easy to quickly test alternative color combinations and find solutions that satisfy both compliance and user experience needs.
By incorporating both WCAG and APCA checks into the design and development workflow, the team was able to address subtle but important accessibility issues proactively, leading to a more readable and user-friendly dashboard.