Home > Software design >  Why is my contrast function calculating the contrast incorrectly?
Why is my contrast function calculating the contrast incorrectly?

Time:01-12

I am trying to create a module that returns the contrast ratio. The intended use is to get a color, and determine whether the contrast against white and black so that I can pick whichever one contrasts more strongly with the color.

I referred to this stack overflow question to help me with it. My version seems to work at first, but when I test it, my results seem to be way off. I compared my output to coolors contrast checker and pasted the result in the comment next to my own result so you can see how far off it is:

// Measure the relative luminance of each RGB value
const reLum = function relativeLuminance(RGB) {
    let newRGB = RGB;
    newRGB /= 255;
    return newRGB <= 0.03928 ?
    newRGB / 12.92 :
    (newRGB   0.055) / 1.055 ** 2.4;
}

// Measure the luminance of the color
const lum = function luminance(r, g, b) {
    const a = [r, g, b].map(reLum);
    return Number(a[0] * 0.2126   a[1] * 0.7152   a[2] * 0.0722).toFixed(3);
}

// Convert hex values to RGB
const hexToRGB = function convertHexToRGB(hex) {
    const result = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(hex);
    return result ?
    [parseInt(result[1], 16), parseInt(result[2], 16), parseInt(result[3], 16)] :
    null;
}

// Measure the contrast between two colors
const contrast = function findContrast(hex1, hex2) {
    const rgb1 = hexToRGB(hex1);
    const rgb2 = hexToRGB(hex2);
    const lum1 = lum(rgb1[0], rgb1[1], rgb1[2]);
    const lum2 = lum(rgb2[0], rgb2[1], rgb2[2]);
    const brightest = Math.max(lum1, lum2);
    const darkest = Math.min(lum1, lum2);
    return (brightest   0.05) / (darkest   0.05);
}

// Contrast is 3.16 against white VS coolors 8.31
console.log(`#922626 contrast against white: ${contrast('#922626', '#FFFFFF')}`);  
// Contrast is 6.18 against black VS coolors 2.53
console.log(`#922626 contrast against black: ${contrast('#922626', '#000000')}`);  

// Contrast is 4.23 against white VS coolors 1.24
console.log(`#102a47 contrast against white: ${contrast('#102a47', '#FFFFFF')}`);  
// Contrast is 4.61 against black VS coolors 14.54
console.log(`#102a47 contrast against black: ${contrast('#102a47', '#000000')}`); 

In my second example, white is clearly supposed to have a bigger contrast with #102a47 since black is nearly indistinguishable from it, but my calculation seems to think that it contrasts equally with white & black.

Obviously, there is some kind of flaw in my calculation, but despite checking the math on W3 here and here, I can't find my mistake.

CodePudding user response:

Missing () for exponent in reLum on this line:

(newRGB 0.055) / 1.055 ** 2.4;

should be

((newRGB 0.055) / 1.055) ** 2.4;

// Measure the relative luminance of each RGB value
const reLum = function relativeLuminance(RGB) {
    let newRGB = RGB;
    newRGB /= 255;
    return newRGB <= 0.03928 ?
    newRGB / 12.92 :
    ((newRGB   0.055) / 1.055) ** 2.4;
}

// Measure the luminance of the color
const lum = function luminance(r, g, b) {
    const a = [r, g, b].map(reLum);
    return Number(a[0] * 0.2126   a[1] * 0.7152   a[2] * 0.0722).toFixed(3);
}

// Convert hex values to RGB
const hexToRGB = function convertHexToRGB(hex) {
    const result = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(hex);
    return result ?
    [parseInt(result[1], 16), parseInt(result[2], 16), parseInt(result[3], 16)] :
    null;
}

// Measure the contrast between two colors
const contrast = function findContrast(hex1, hex2) {
    const rgb1 = hexToRGB(hex1);
    const rgb2 = hexToRGB(hex2);
    const lum1 = lum(rgb1[0], rgb1[1], rgb1[2]);
    const lum2 = lum(rgb2[0], rgb2[1], rgb2[2]);
    const brightest = Math.max(lum1, lum2);
    const darkest = Math.min(lum1, lum2);
    return (brightest   0.05) / (darkest   0.05);
}

// Contrast is 3.16 against white VS coolors 8.31
console.log(`#922626 contrast against white: ${contrast('#922626', '#FFFFFF')}`);  
// Contrast is 6.18 against black VS coolors 2.53
console.log(`#922626 contrast against black: ${contrast('#922626', '#000000')}`);  

// Contrast is 4.23 against white VS coolors 14.54
console.log(`#102a47 contrast against white: ${contrast('#102a47', '#FFFFFF')}`);  
// Contrast is 4.61 against black VS coolors 1.24
console.log(`#102a47 contrast against black: ${contrast('#102a47', '#000000')}`); 

  • Related