Last active
September 11, 2023 05:18
-
-
Save hail2u/a1fb620d4826c5b476180ee6285618a5 to your computer and use it in GitHub Desktop.
Get contrast of colors using APCA (Advanced Perceptual Contrast Algorithm)
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
// https://github.com/Myndex/SAPC-APCA#the-plain-english-steps-are | |
// Example: | |
// const contrast = getAPCAContrast("rgb(255, 255, 255)", "rgb(136, 136, 136)"); | |
// This returns `66.89346308821438` (66.893%) | |
// SAPC-APCA README says: | |
// > #888 vs #fff • 66.89346308821438 | |
// 80% means 7:1 in WCAG 2.0 | |
// 60% means 4.5:1 in WCAG 2.0 | |
// Web UI: https://hail2u.net/pub/test/702.html | |
const linearize = (val) => (val / 255.0) ** 2.4; | |
const clampLuminance = (luminance) => { | |
const blkThrs = 0.03; | |
const blkClmp = 1.45; | |
if (luminance > blkThrs) { | |
return luminance; | |
} | |
return Math.abs(blkThrs - luminance) ** blkClmp + luminance; | |
}; | |
const getLuminance = (color) => { | |
const [red, green, blue] = color.match(/\d+/gu); | |
const y = | |
0.2126729 * linearize(red) + | |
0.7151522 * linearize(green) + | |
0.072175 * linearize(blue); | |
return clampLuminance(y); | |
}; | |
const getContrast = (background, foreground) => { | |
const deltaYmin = 0.0005; | |
const scale = 1.25; | |
const backgroundLuminance = getLuminance(background); | |
const foregroundLuminance = getLuminance(foreground); | |
if (Math.abs(backgroundLuminance - foregroundLuminance) < deltaYmin) { | |
return 0.0; | |
} | |
if (backgroundLuminance > foregroundLuminance) { | |
return (backgroundLuminance ** 0.55 - foregroundLuminance ** 0.58) * scale; | |
} | |
if (backgroundLuminance < foregroundLuminance) { | |
return (backgroundLuminance ** 0.62 - foregroundLuminance ** 0.57) * scale; | |
} | |
return 0.0; | |
}; | |
const scaleContrast = (contrast) => { | |
const loClip = 0.001; | |
const loConThresh = 0.078; | |
const loConFactor = 1 / loConThresh; | |
const loConOffset = 0.06; | |
const absContrast = Math.abs(contrast); | |
if (absContrast < loClip) { | |
return 0.0; | |
} | |
if (absContrast <= loConThresh) { | |
return contrast - contrast * loConFactor * loConOffset; | |
} | |
if (contrast > loConThresh) { | |
return contrast - loConOffset; | |
} | |
if (contrast < -loConThresh) { | |
return contrast + loConOffset; | |
} | |
return 0.0; | |
}; | |
const getAPCAContrast = (background, foreground) => { | |
const contrast = getContrast(background, foreground); | |
const scaledContrast = scaleContrast(contrast); | |
return scaledContrast * 100; | |
}; |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Hello @hail2u
I just wanted to let you know there are newer constants than those shown here.
New Constants (March 2021)
If you prefer, here is the current set as objects:
NPM Package & More
Also, we now have an NPM package available:
npm i apca-w3
And if you have a tool up an running, please feel free to add it to the list here:
Myndex/SAPC-APCA#51
Thank you!
Andy