diff --git a/packages/shared/styles/color.ts b/packages/shared/styles/color.ts index 3dfbc42be..6301ecb51 100644 --- a/packages/shared/styles/color.ts +++ b/packages/shared/styles/color.ts @@ -81,38 +81,48 @@ export const getTextColor = ( darkTextColor, lightTextColor ): string => { - // Convert color from hex to RGB. - const getRGB = (c: string | number): number => { - return parseInt(c as string, 16) || (c as number); - }; - - // Convert to sRGB and apply gamma correction. - const getsRGB = (c: string): number => { - const rgb = getRGB(c) / 255; - return rgb <= 0.03928 ? rgb / 12.92 : Math.pow((rgb + 0.055) / 1.055, 2.4); - }; - - // Calculate relative luminance. - const getLuminance = (hexColor: string): number => { - return ( - 0.2126 * getsRGB(hexColor.slice(1, 3)) + - 0.7152 * getsRGB(hexColor.slice(3, 5)) + - 0.0722 * getsRGB(hexColor.slice(5, 7)) - ); - }; - - // Use relative luminance to compare color contrast. const getContrast = (f: string, b: string): number => { + // Use relative luminance to compare color contrast. + const getLuminance = (hexColor: string): number => { + // Convert to sRGB and apply gamma correction. + const getRGB = (c: string | number): number => + parseInt(c as string, 16) || (c as number); + const getsRGB = (c: string): number => { + const rgb = getRGB(c) / 255; + return rgb <= 0.03928 + ? rgb / 12.92 + : Math.pow((rgb + 0.055) / 1.055, 2.4); + }; + + return ( + 0.2126 * getsRGB(hexColor.slice(1, 3)) + + 0.7152 * getsRGB(hexColor.slice(3, 5)) + + 0.0722 * getsRGB(hexColor.slice(5, 7)) + ); + }; + const L1 = getLuminance(f); const L2 = getLuminance(b); - // Ratio formula is defined by WCAG guidelines return (Math.max(L1, L2) + 0.05) / (Math.min(L1, L2) + 0.05); }; - const LIGHT_COLOR = getContrast(bgColor, lightTextColor); - const DARK_COLOR = getContrast(bgColor, darkTextColor); + // WCAG 2.2 color contrast standard for normal text. + const MIN_NORMAL_CONTRAST = 4.5; + + const contrastWithDarkText = getContrast(bgColor, darkTextColor); + const contrastWithLightText = getContrast(bgColor, lightTextColor); + + if ( + contrastWithLightText >= MIN_NORMAL_CONTRAST && + contrastWithDarkText < MIN_NORMAL_CONTRAST + ) { + return lightTextColor; + } + // Determine which color has the highest contrast ratio and return that color. - return LIGHT_COLOR > DARK_COLOR ? lightTextColor : darkTextColor; + return contrastWithDarkText > MIN_NORMAL_CONTRAST + ? darkTextColor + : lightTextColor; }; // Assumes we always want our default hover colors to be lower