Last active
June 6, 2024 19:35
-
-
Save darcher-/9011ff00b6fa499a36ec924b5eaa62c3 to your computer and use it in GitHub Desktop.
Accessibility contrast rating utility.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/** | |
* Defines a color scheme with a text color and a backdrop color. | |
* @type {Object} | |
* @property {string} textColor - The hexadecimal color value for the text. | |
* @property {string} backDropColor - The hexadecimal color value for the backdrop. | |
*/ | |
const COLOR_SCHEME = { | |
textColor: "#000", | |
backDropColor: "#fff", | |
}; | |
/** | |
* An object that contains information about the contrast ratio between a text color and a backdrop color, including whether the contrast meets WCAG AA and AAA standards. | |
* @type {Object} | |
* @property {string} textColor - The hexadecimal color value for the text. | |
* @property {string} backDropColor - The hexadecimal color value for the backdrop. | |
* @property {boolean} AA - Whether the contrast ratio meets the WCAG AA standard. | |
* @property {boolean} AAA - Whether the contrast ratio meets the WCAG AAA standard. | |
* @property {number} A11Y_WCAG_RATIO - The calculated contrast ratio between the text color and backdrop color. | |
*/ | |
const RATIO_DATAUM = Object.freeze({ | |
...COLOR_SCHEME, | |
AA: meetsWCAGContrastLevel( | |
COLOR_SCHEME.backDropColor, | |
COLOR_SCHEME.textColor, | |
'AA', | |
), | |
AAA: meetsWCAGContrastLevel( | |
COLOR_SCHEME.backDropColor, | |
COLOR_SCHEME.textColor, | |
'AAA' | |
), | |
A11Y_WCAG_RATIO: calculateContrastRatio( | |
COLOR_SCHEME.backDropColor, | |
COLOR_SCHEME.textColor, | |
), | |
}); | |
console.log(RATIO_DATAUM); | |
//! Utilities | |
/** | |
* Converts a hexadecimal color code to an RGB color object. | |
* @param {string} hexadecimal - The hexadecimal color code to convert. | |
* @returns {Object} - An object with `r`, `g`, and `b` properties representing the RGB color values. | |
*/ | |
function hexToRgb(hexadecimal) { | |
const formattedHexCode = hexadecimal.replace(/^#?([a-f\d])([a-f\d])([a-f\d])$/i, | |
(m, r, g, b) => r + r + g + g + b + b | |
); | |
const rgbChannelColors = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec( | |
formattedHexCode | |
); | |
return { | |
r: parseInt(rgbChannelColors[1], 16), | |
g: parseInt(rgbChannelColors[2], 16), | |
b: parseInt(rgbChannelColors[3], 16), | |
}; | |
} | |
/** | |
* Calculates the relative luminance of a color channel value. | |
* @param {number} channel - The color channel value (0-255). | |
* @returns {number} - The relative luminance of the color channel. | |
*/ | |
function calculateRelativeChannelLuminance(channel) { | |
return (channel /= 255) <= 0.03928 ? channel / 12.92 : Math.pow( | |
(channel + 0.055) / 1.055, 2.4 | |
); | |
} | |
/** | |
* Calculates the relative luminance of an RGB color. | |
* @param {number} r - The red color channel value (0-255). | |
* @param {number} g - The green color channel value (0-255). | |
* @param {number} b - The blue color channel value (0-255). | |
* @returns {number} - The relative luminance of the RGB color. | |
*/ | |
function relativeRgbLumLevel(r, g, b) { | |
const [red, green, blue] = [r, g, b].map( | |
calculateRelativeChannelLuminance | |
); | |
const G = 0.7152 * green; | |
const B = 0.0722 * blue; | |
const R = 0.2126 * red; | |
return (R + G + B); | |
} | |
/** | |
* Retrieves the RGB color channels for two hexadecimal color values. | |
* @param {string} set1 - The first hexadecimal color value. | |
* @param {string} set2 - The second hexadecimal color value. | |
* @returns {object} - An object containing the red, green, and blue color channels for both color values. | |
*/ | |
function getRgbChannels(set1, set2) { | |
const { r: red1, g: green1, b: blue1 } = hexToRgb(set1); | |
const { r: red2, g: green2, b: blue2 } = hexToRgb(set2); | |
return { | |
green: [green1, green2], | |
blue: [blue1, blue2], | |
red: [red1, red2], | |
} | |
} | |
/** | |
* Calculates the range of vibrance between two sets of RGB color channels. | |
* @param {object} param - An object containing the red, green, and blue color channels for two color values. | |
* @param {number[]} param.g - The green color channel values for the two colors. | |
* @param {number[]} param.b - The blue color channel values for the two colors. | |
* @param {number[]} param.r - The red color channel values for the two colors. | |
* @returns {object} - An object containing the brighter and darker vibrance values. | |
*/ | |
function rangeOfVibrance({ g, b, r }) { | |
const vibrance1 = relativeRgbLumLevel(r[0], g[0], b[0]); | |
const vibrance2 = relativeRgbLumLevel(r[1], g[1], b[1]); | |
return { | |
brighter: Math.max(vibrance1, vibrance2) + 0.05, | |
darker: Math.min(vibrance1, vibrance2) + 0.05, | |
} | |
} | |
/** | |
* Calculates the contrast ratio between two hexadecimal color values. | |
* @param {string} hex1 - The first hexadecimal color value. | |
* @param {string} hex2 - The second hexadecimal color value. | |
* @returns {number} - The contrast ratio between the two colors. | |
*/ | |
function calculateContrastRatio(hex1, hex2) { | |
const { red, green, blue } = getRgbChannels(hex1, hex2); | |
const { brighter, darker } = rangeOfVibrance({ | |
g: [...green], | |
b: [...blue], | |
r: [...red], | |
}); | |
return (brighter / darker); | |
} | |
/** | |
* Checks if the contrast ratio between two hexadecimal color values meets the specified WCAG contrast level. | |
* @param {string} hex1 - The first hexadecimal color value. | |
* @param {string} hex2 - The second hexadecimal color value. | |
* @param {'AA'|'AAA'} level - The WCAG contrast level to check against ('AA' or 'AAA'). | |
* @returns {boolean} - True if the contrast ratio meets the specified WCAG contrast level, false otherwise. | |
*/ | |
function meetsWCAGContrastLevel(hex1, hex2, level) { | |
const contrastRatio = calculateContrastRatio(hex1, hex2); | |
const requiredRatio = level === 'AA' ? 4.5 : 7; | |
return contrastRatio >= requiredRatio; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment