Created
April 15, 2019 21:52
-
-
Save iaman/00284c8d385f8599dca12fb991fe2ba5 to your computer and use it in GitHub Desktop.
An importable library for dealing with HEX/RGB colors and getting contrast info
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
const VALID_HEX_CHARS = { | |
"0": true, | |
"1": true, | |
"2": true, | |
"3": true, | |
"4": true, | |
"5": true, | |
"6": true, | |
"7": true, | |
"8": true, | |
"9": true, | |
"A": true, | |
"B": true, | |
"C": true, | |
"D": true, | |
"E": true, | |
"F": true | |
} | |
const getRGBComponentLuminance = (component) => { | |
if (typeof component == "string") component = parseInt(component); | |
if (component < 0) component = 0; | |
else if (component > 255) component = 1; | |
else component = component / 255; | |
if (component <= 0.03928) return component / 12.92; | |
else return Math.pow((component + 0.055) / 1.055, 2.4); | |
} | |
const HEXComponentToRGB = (component) => { | |
if (component.length == 1) component = `${component}${component}`; | |
return parseInt(component, 16); | |
} | |
const RGBComponentToHEX = (component) => { | |
if (typeof component == "string") component = parseInt(component); | |
const tempHEX = component.toString(16); | |
return (tempHEX.length == 1) ? `0${tempHEX}` : tempHEX; | |
} | |
const relativeLuminance = (color) => { | |
if (validHEXColor(color)) color = parseRGBFromHEX(color); | |
const splitColor = splitRGB(color); | |
const redLuminance = getRGBComponentLuminance(splitColor[0]); | |
const greenLuminance = getRGBComponentLuminance(splitColor[1]); | |
const blueminance = getRGBComponentLuminance(splitColor[2]); | |
return 0.2126 * redLuminance + 0.7152 * greenLuminance + 0.0722 * blueminance; | |
} | |
const splitHEX = (color) => { | |
if (color.length == 4) return color.replace("#","").split(""); | |
else return color.replace("#","").match(/.{1,2}/g); | |
} | |
const splitRGB = (color) => { | |
return color.replace("rgb(","").replace("rgba(","").replace(")","").split(","); | |
} | |
export var validHEXColor = (color) => { | |
let valid = false; | |
if (typeof color == "string") { | |
const splitColor = color.split(""); | |
const length = splitColor.length; | |
const includesHEX = splitColor[0] == "#"; | |
if (includesHEX ? (length == 4 || length == 7) : (length == 3 || length == 6)) { | |
let i = includesHEX ? 1 : 0; | |
while (i < length) { | |
if (typeof VALID_HEX_CHARS[splitColor[i].toUpperCase()] == "undefined") break; | |
i++; | |
} | |
valid = (i == length && length != 0); | |
} | |
} | |
return valid; | |
}; | |
export var validRGBColor = (color) => { | |
let valid = false; | |
if (typeof color == "string") { | |
const splitColor = splitRGB(color); | |
const length = splitColor.length; | |
if (length == 3 || length == 4) { | |
let i = 0; | |
while (i < length) { | |
if (isNaN((i == 3) ? parseFloat(splitColor[3]) : parseInt(splitColor[i]))) break; | |
i++; | |
} | |
valid = (i == length); | |
} | |
} | |
return valid; | |
} | |
export var parseHEXFromRGB = (color) => { | |
let HEX = "#"; | |
const splitColor = splitRGB(color); | |
for (let i = 0; i < 3; i++) { | |
HEX += RGBComponentToHEX(splitColor[i]); | |
} | |
if (validHEXColor(HEX)) return HEX; | |
} | |
export var parseRGBFromHEX = (color) => { | |
let RGB = ""; | |
const splitColor = splitHEX(color); | |
for (let i = 0; i < 3; i++) { | |
RGB += HEXComponentToRGB(splitColor[i]); | |
if (i != 2) RGB += ", "; | |
} | |
return `rgb(${RGB})`; | |
} | |
export var getFullHEXColor = (color) => { | |
const splitColor = color.split(""); | |
const length = splitColor.length; | |
const includesHEX = splitColor[0] == "#"; | |
let fullHEXColor = "#"; | |
let i = includesHEX ? 1 : 0; | |
while (i < length) { | |
fullHEXColor += splitColor[i]; | |
if (includesHEX && (length == 3 || length == 4)) fullHEXColor += splitColor[i]; | |
i++; | |
} | |
return fullHEXColor; | |
} | |
const getContrastRatio = (background, foreground) => { | |
const l1 = relativeLuminance(background) + 0.05; | |
const l2 = relativeLuminance(foreground) + 0.05; | |
if (l1 > l2) return l1 / l2; | |
else return l2 / l1; | |
} | |
export var contrastRatio = (background, foreground) => { | |
return getContrastRatio(background, foreground).toFixed(2); | |
} | |
export var passesWCAGAA = (background, foreground) => { | |
const contrastRatio = getContrastRatio(background, foreground); | |
return { | |
normal: contrastRatio >= 4.5, | |
large: contrastRatio >= 3 | |
} | |
} | |
export var passesWCAGAAA = (background, foreground) => { | |
const contrastRatio = getContrastRatio(background, foreground); | |
return { | |
normal: contrastRatio >= 7, | |
large: contrastRatio >= 4.5 | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment