Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Background color is not computed correctly when there are multiple layers of non-opaque background colors #2924

Closed
heryandi opened this issue May 7, 2021 · 7 comments
Labels
color contrast Color contrast issues fix Bug fixes pr A pr has been created for the issue rules Issue or false result from an axe-core rule

Comments

@heryandi
Copy link

heryandi commented May 7, 2021

Product: axe-core

Expectation: I expect axe-core to use the right background color value (as can be observed by a color-picker) for color contrast calculation.

Actual: axe-core doesn't seem to calculate the right background color. Seems like it's only wrong when there are multiple layers of non-opaque background colors involved.

Motivation: This should be fixed so the correct color contrast value can be computed.

    axe-core version: 4.2.0

Sample test cases:

  • Case 1
<html>
    <body>
        <div style="background-color: red;">
            <!-- 'blue' with 0.3 alpha -->
            <div style="background-color: rgba(0, 0, 255, 0.3);">
                <!-- 'green' with 0.3 alpha -->
                <div style="background-color: rgba(0, 128, 0, 0.3);">
                    <p>Some text</p>
                </div>
            </div>
        </div>
    </body>
</html>

Expected background color (as picked up by a color-picker): #7C2736
Background-color computed by axe-core (bgColor inside the data field): #7D145B

  • Case 2
<html>
    <body>
        <div style="background-color: rgba(255, 255, 255, 1.0);">
            <!-- 'green' with 0.25 alpha -->
            <div style="background-color: rgba(0, 128, 0, 0.25);">
                <!-- 'red' with 0.5 alpha -->
                <div style="background-color: rgba(255, 0, 0, 0.5);">
                    <p>Some text</p>
                </div>
            </div>
        </div>
    </body>
</html>

Expected background color (as picked up by a color-picker): #DF6F5F
Background-color computed by axe-core (bgColor inside the data field): #AF8860

I think (but not sure) this is because the flattenColors function doesn't apply the simple alpha compositing formula.

I am using a Chrome extension for my color-picker, if that matters: https://chrome.google.com/webstore/detail/colorpick-eyedropper/ohcpnigalekghcmgcdcenkpelffpdolg

@WilcoFiers
Copy link
Contributor

Thank you for reporting @heryandi. I can't say I've ever checked the accuracy of the flattenColor function, but I can see you're right about it not being accurate. I'll definitely look into this.

@WilcoFiers WilcoFiers added color contrast Color contrast issues fix Bug fixes rules Issue or false result from an axe-core rule labels May 8, 2021
@dylanb
Copy link
Contributor

dylanb commented Jun 28, 2021

Can we see code pen for the HTML and CSS for this? I get all sorts of different colors uing the OS X built-in color sampling app. None of them match the reported colors.

The algorithm supplied is a candidate recommendation. The current standard is https://www.w3.org/TR/SVG11/masking.html#SimpleAlphaBlending

Which is referenced here https://www.w3.org/TR/css-color-3/#alpha

@heryandi
Copy link
Author

heryandi commented Jun 29, 2021

Hi, here are the codepen links for those two example cases:

No CSS needed since those examples use only inline CSS.

I tried using gpick instead of the previous Chrome extension, but the colors picked up are exactly the same as the Chrome extension. (I don't have a Mac, so I can't try pick the colors there)

@jribbens
Copy link

Here's another real-world case of what seems to be the same issue: https://www.bracknell-forest.gov.uk/health-and-social-care/dementia-support
axe is complaining that some of the text is definitely bad contrast when in reality it is #333 on #fff .

@straker
Copy link
Contributor

straker commented Oct 5, 2021

Just as a note, different browsers will render color slightly differently based on a few things. For example, Chrome defaults to use the color profile of the operating system, which can result in a different rendering. Take the following code:

<div style="display: flex;flex-direction: row;">
  <div style="background-color: rgba(255, 255, 255, 1.0);">
    <div style="background-color: rgba(255, 0, 0, 0.5);">
      <p>Some text</p>
    </div>
  </div>
  <div style="background-color: rgba(255, 127, 127, 1); width: 100%; height: 50px;"></div>
</div>

Now following the CSS spec for color blending (https://www.w3.org/TR/compositing-1/#blending and https://www.w3.org/TR/compositing-1/#simplealphacompositing), the algorithm for computing the blending of two colors is as follows:

// Simple Alpha Compositing
// Rrgb × Ra = Srgb × Sa + Drgb × Da × (1 − Sa)
// Ra = Sa + Da × (1 − Sa)
function simpleAlphaCompositing(S, D) {
  const r = S[3] * S[0] + (1 - S[3]) * D[3] * D[0];
  const g = S[3] * S[1] + (1 - S[3]) * D[3] * D[1];
  const b = S[3] * S[2] + (1 - S[3]) * D[3] * D[2];
  const a = Math.min(S[3] + D[3] * (1 - S[3]), 1)

  return [r, g, b, a]
}

const S = [255, 0, 0, 0.5];
const D = [255, 255, 255, 1.0];

simpleAlphaCompositing(S, D)

Which returns the result of mixing 50% red with pure white of rgba(255, 127.5, 127.5, 1). That is the value of the 2nd div (rounding down). So in theory the two colors should be equal to each other. However, due to how the browser renders the color we can get a different result (shown below with Chrome, Firefox, and Safari respectively)

image

Only in Firefox does the color match. But if we change how Chrome renders the colors by forcing it to use the sRGB color profile (chrome://flags/ and Force Color Profile, select sRGB), then Chrome will now also render the color correctly:

image

Also, the color picker tool for Mac does not correctly return the color, so is a bit unreliable (it shows the final color to be rgb(239, 134, 131)

image

@straker
Copy link
Contributor

straker commented Oct 5, 2021

I believe I have determined the issue. When blending multiple colors, our code finds the visual stack order of the elements (in this case it would be: [p, div#red, div#green, div#white]) and then flattens the colors in that order (top down). However, this produces the incorrect result as doing so with the provided Case 2 html produces rgba(175.3125, 105.625, 95.625, 1):

image

Instead, we need to flatten the colors from the bottom up, which results in the correct final color rgba(223.125, 111.625, 95.625, 1)

image

@straker straker added the pr A pr has been created for the issue label Oct 6, 2021
@padmavemulapati
Copy link

Validated with the latest axe-core develop branch code base, and I am seeing the expected color pickers for the both cases provided.

image

image
image

@WilcoFiers WilcoFiers added this to the Axe-core 4.4 milestone Nov 10, 2021
@straker straker removed this from the Axe-core 4.4 milestone Nov 10, 2021
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
color contrast Color contrast issues fix Bug fixes pr A pr has been created for the issue rules Issue or false result from an axe-core rule
Projects
None yet
Development

No branches or pull requests

7 participants