diff --git a/lib/commons/color/flatten-colors.js b/lib/commons/color/flatten-colors.js index 2c3de0e033..a87de6656f 100644 --- a/lib/commons/color/flatten-colors.js +++ b/lib/commons/color/flatten-colors.js @@ -1,11 +1,66 @@ import Color from './color'; +// clamp a value between two numbers (inclusive) +function clamp(value, min, max) { + return Math.min(Math.max(min, value), max); +} + // how to combine background and foreground colors together when using // the CSS property `mix-blend-mode`. Defaults to `normal` // @see https://www.w3.org/TR/compositing-1/#blendingseparable const blendFunctions = { normal(Cb, Cs) { return Cs; + }, + multiply(Cb, Cs) { + // @see https://www.w3.org/TR/compositing-1/#blendingmultiply + return Cs * Cb; + }, + screen(Cb, Cs) { + // @see https://www.w3.org/TR/compositing-1/#blendingscreen + return Cb + Cs - Cb * Cs; + }, + overlay(Cb, Cs) { + // @see https://www.w3.org/TR/compositing-1/#blendingoverlay + return this['hard-light'](Cs, Cb); + }, + darken(Cb, Cs) { + // @see https://www.w3.org/TR/compositing-1/#blendingdarken + return Math.min(Cb, Cs); + }, + lighten(Cb, Cs) { + // @see https://www.w3.org/TR/compositing-1/#blendinglighten + return Math.max(Cb, Cs); + }, + 'color-dodge'(Cb, Cs) { + // @see https://www.w3.org/TR/compositing-1/#blendingcolordodge + return Cb === 0 ? 0 : Cs === 1 ? 1 : Math.min(1, Cb / (1 - Cs)); + }, + 'color-burn'(Cb, Cs) { + // @see https://www.w3.org/TR/compositing-1/#blendingcolorburn + return Cb === 1 ? 1 : Cs === 0 ? 0 : 1 - Math.min(1, (1 - Cb) / Cs); + }, + 'hard-light'(Cb, Cs) { + // @see https://www.w3.org/TR/compositing-1/#blendinghardlight + + return Cs <= 0.5 ? this.multiply(Cb, 2 * Cs) : this.screen(Cb, 2 * Cs - 1); + }, + 'soft-light'(Cb, Cs) { + // @see https://www.w3.org/TR/compositing-1/#blendingsoftlight + if (Cs <= 0.5) { + return Cb - (1 - 2 * Cs) * Cb * (1 - Cb); + } else { + const D = Cb <= 0.25 ? ((16 * Cb - 12) * Cb + 4) * Cb : Math.sqrt(Cb); + return Cb + (2 * Cs - 1) * (D - Cb); + } + }, + difference(Cb, Cs) { + // @see https://www.w3.org/TR/compositing-1/#blendingdifference + return Math.abs(Cb - Cs); + }, + exclusion(Cb, Cs) { + // @see https://www.w3.org/TR/compositing-1/#blendingexclusion + return Cb + Cs - 2 * Cb * Cs; } }; @@ -19,12 +74,12 @@ const blendFunctions = { // @see https://www.w3.org/TR/compositing-1/#blending // @see https://ciechanow.ski/alpha-compositing/ function simpleAlphaCompositing(Cs, αs, Cb, αb, blendMode) { - // RGB color space doesn't have decimal values so we will follow what browsers do and round - // e.g. rgb(255.2, 127.5, 127.8) === rgb(255, 128, 128) - return Math.round( + return ( αs * (1 - αb) * Cs + - αs * αb * blendFunctions[blendMode](Cb, Cs) + - (1 - αs) * αb * Cb + // Note: Cs and Cb values need to be between 0 and 1 inclusive for the blend function + // @see https://www.w3.org/TR/compositing-1/#simplealphacompositing + αs * αb * blendFunctions[blendMode](Cb / 255, Cs / 255) * 255 + + (1 - αs) * αb * Cb ); } @@ -63,12 +118,22 @@ function flattenColors(fgColor, bgColor, blendMode = 'normal') { // formula: αo = αs + αb x (1 - αs) // clamp alpha between 0 and 1 - const a = Math.max( - 0, - Math.min(fgColor.alpha + bgColor.alpha * (1 - fgColor.alpha), 1) - ); + const αo = clamp(fgColor.alpha + bgColor.alpha * (1 - fgColor.alpha), 0, 1); + + // simple alpha compositing gives premultiplied values, but our Color + // constructor takes unpremultiplied values. So we need to divide the + // final color values by the final alpha + // formula: Co = co / αo + // @see https://www.w3.org/TR/compositing-1/#simplealphacompositing + // @see https://github.com/w3c/fxtf-drafts/issues/440#issuecomment-956418953 + // + // RGB color space doesn't have decimal values so we will follow what browsers do and round + // e.g. rgb(255.2, 127.5, 127.8) === rgb(255, 128, 128) + const Cr = Math.round(r / αo); + const Cg = Math.round(g / αo); + const Cb = Math.round(b / αo); - return new Color(r, g, b, a); + return new Color(Cr, Cg, Cb, αo); } export default flattenColors; diff --git a/lib/commons/color/get-background-color.js b/lib/commons/color/get-background-color.js index ff2a28bc87..499511b770 100644 --- a/lib/commons/color/get-background-color.js +++ b/lib/commons/color/get-background-color.js @@ -27,8 +27,9 @@ export default function getBackgroundColor( ) { let bgColors = getTextShadowColors(elm, { minRatio: shadowOutlineEmMax }); if (bgColors.length) { - bgColors = [bgColors.reduce(flattenShadowColors)]; + bgColors = [{ color: bgColors.reduce(flattenShadowColors) }]; } + const elmStack = getBackgroundStack(elm); // Search the stack until we have an alpha === 1 background @@ -53,7 +54,11 @@ export default function getBackgroundColor( if (bgColor.alpha !== 0) { // store elements contributing to the br color. bgElms.push(bgElm); - bgColors.unshift(bgColor); + const blendMode = bgElmStyle.getPropertyValue('mix-blend-mode'); + bgColors.unshift({ + color: bgColor, + blendMode: normalizeBlendMode(blendMode) + }); // Exit if the background is opaque return bgColor.alpha === 1; @@ -72,14 +77,28 @@ export default function getBackgroundColor( ); bgColors.unshift(...pageBgs); + // default to white if bgColors is empty + if (bgColors.length === 0) { + return new Color(255, 255, 255, 1); + } // Mix the colors together. Colors must be mixed in bottom up // order (background to foreground order) to produce the correct // result. // @see https://github.com/dequelabs/axe-core/issues/2924 - var colors = bgColors.reduce((bgColor, fgColor) => { - return flattenColors(fgColor, bgColor); + const blendedColor = bgColors.reduce((bgColor, fgColor) => { + return flattenColors( + fgColor.color, + bgColor.color instanceof Color ? bgColor.color : bgColor, + fgColor.blendMode + ); }); - return colors; + + // default page background is white which must be mixed last + // @see https://www.w3.org/TR/compositing-1/#pagebackdrop + return flattenColors( + blendedColor.color instanceof Color ? blendedColor.color : blendedColor, + new Color(255, 255, 255, 1) + ); } /** @@ -99,6 +118,9 @@ function elmPartiallyObscured(elm, bgElm, bgColor) { return obscured; } +function normalizeBlendMode(blendmode) { + return !!blendmode ? blendmode : undefined; +} /** * Get the page background color. * @private @@ -131,24 +153,30 @@ function getPageBackgroundColors(elm, stackContainsBody) { const bodyBgColor = getOwnBackgroundColor(bodyStyle); const bodyBgColorApplies = bodyBgColor.alpha !== 0 && visuallyContains(elm, body); - if ( (bodyBgColor.alpha !== 0 && htmlBgColor.alpha === 0) || (bodyBgColorApplies && bodyBgColor.alpha !== 1) ) { - pageColors.unshift(bodyBgColor); + pageColors.unshift({ + color: bodyBgColor, + blendMode: normalizeBlendMode( + bodyStyle.getPropertyValue('mix-blend-mode') + ) + }); } if ( htmlBgColor.alpha !== 0 && (!bodyBgColorApplies || (bodyBgColorApplies && bodyBgColor.alpha !== 1)) ) { - pageColors.unshift(htmlBgColor); + pageColors.unshift({ + color: htmlBgColor, + blendMode: normalizeBlendMode( + htmlStyle.getPropertyValue('mix-blend-mode') + ) + }); } } - // default page background is white - pageColors.unshift(new Color(255, 255, 255, 1)); - return pageColors; } diff --git a/test/commons/color/flatten-colors.js b/test/commons/color/flatten-colors.js index bceb351f52..3343eda8b5 100644 --- a/test/commons/color/flatten-colors.js +++ b/test/commons/color/flatten-colors.js @@ -38,9 +38,251 @@ describe('color.flattenColors', function() { assert.equal(flat5.alpha, 1); var flat6 = axe.commons.color.flattenColors(quarterLightGreen, halfRed); - assert.equal(flat6.red, 96); - assert.equal(flat6.green, 32); + assert.equal(flat6.red, 153); + assert.equal(flat6.green, 51); assert.equal(flat6.blue, 0); assert.equal(flat6.alpha, 0.625); }); }); + +describe('color.flattenColors mix-blend-mode functions', function() { + 'use strict'; + + var colourOne = new axe.commons.color.Color(216, 22, 22, 1); + var colourTwo = new axe.commons.color.Color(114, 129, 114, 0.25); + + var colourThree = new axe.commons.color.Color(211, 162, 180, 1); + var colourFour = new axe.commons.color.Color(115, 255, 0, 0.5); + + it('should flatten colors correctly using blend mode: multiply', function() { + var flatten = axe.commons.color.flattenColors( + colourTwo, + colourOne, + 'multiply' + ); + assert.equal(flatten.red, 186); + assert.equal(flatten.green, 19); + assert.equal(flatten.blue, 19); + assert.equal(flatten.alpha, 1); + + var flattenTwo = axe.commons.color.flattenColors( + colourFour, + colourThree, + 'multiply' + ); + assert.equal(flattenTwo.red, 153); + assert.equal(flattenTwo.green, 162); + assert.equal(flattenTwo.blue, 90); + assert.equal(flattenTwo.alpha, 1); + }); + + it('should flatten colors correctly using blend mode: screen', function() { + var flatten = axe.commons.color.flattenColors( + colourTwo, + colourOne, + 'screen' + ); + assert.equal(flatten.red, 220); + assert.equal(flatten.green, 51); + assert.equal(flatten.blue, 48); + assert.equal(flatten.alpha, 1); + + var flattenTwo = axe.commons.color.flattenColors( + colourFour, + colourThree, + 'screen' + ); + assert.equal(flattenTwo.red, 221); + assert.equal(flattenTwo.green, 209); + assert.equal(flattenTwo.blue, 180); + assert.equal(flattenTwo.alpha, 1); + }); + + it('should flatten colors correctly using blend mode: overlay', function() { + var flatten = axe.commons.color.flattenColors( + colourTwo, + colourOne, + 'overlay' + ); + assert.equal(flatten.red, 215); + assert.equal(flatten.green, 22); + assert.equal(flatten.blue, 21); + assert.equal(flatten.alpha, 1); + }); + + it('should flatten colors correctly using blend mode: darken', function() { + var flatten = axe.commons.color.flattenColors( + colourTwo, + colourOne, + 'darken' + ); + assert.equal(flatten.red, 191); + assert.equal(flatten.green, 22); + assert.equal(flatten.blue, 22); + assert.equal(flatten.alpha, 1); + + var flattenTwo = axe.commons.color.flattenColors( + colourFour, + colourThree, + 'darken' + ); + assert.equal(flattenTwo.red, 163); + assert.equal(flattenTwo.green, 162); + assert.equal(flattenTwo.blue, 90); + assert.equal(flattenTwo.alpha, 1); + }); + + it('should flatten colors correctly using blend mode: lighten', function() { + var flatten = axe.commons.color.flattenColors( + colourTwo, + colourOne, + 'lighten' + ); + assert.equal(flatten.red, 216); + assert.equal(flatten.green, 49); + assert.equal(flatten.blue, 45); + assert.equal(flatten.alpha, 1); + + var flattenTwo = axe.commons.color.flattenColors( + colourFour, + colourThree, + 'lighten' + ); + assert.equal(flattenTwo.red, 211); + assert.equal(flattenTwo.green, 209); + assert.equal(flattenTwo.blue, 180); + assert.equal(flattenTwo.alpha, 1); + }); + + it('should flatten colors correctly using blend mode: color-dodge', function() { + var flatten = axe.commons.color.flattenColors( + colourTwo, + colourOne, + 'color-dodge' + ); + assert.equal(flatten.red, 226); + assert.equal(flatten.green, 28); + assert.equal(flatten.blue, 26); + assert.equal(flatten.alpha, 1); + + var flattenTwo = axe.commons.color.flattenColors( + colourFour, + colourThree, + 'color-dodge' + ); + assert.equal(flattenTwo.red, 233); + assert.equal(flattenTwo.green, 209); + assert.equal(flattenTwo.blue, 180); + assert.equal(flattenTwo.alpha, 1); + }); + + it('should flatten colors correctly using blend mode: color-burn', function() { + var flatten = axe.commons.color.flattenColors( + colourTwo, + colourOne, + 'color-burn' + ); + assert.equal(flatten.red, 204); + assert.equal(flatten.green, 17); + assert.equal(flatten.blue, 17); + assert.equal(flatten.alpha, 1); + + var flattenTwo = axe.commons.color.flattenColors( + colourFour, + colourThree, + 'color-burn' + ); + assert.equal(flattenTwo.red, 184); + assert.equal(flattenTwo.green, 162); + assert.equal(flattenTwo.blue, 90); + assert.equal(flattenTwo.alpha, 1); + }); + + it('should flatten colors correctly using blend mode: hard-light', function() { + var flatten = axe.commons.color.flattenColors( + colourTwo, + colourOne, + 'hard-light' + ); + assert.equal(flatten.red, 210); + assert.equal(flatten.green, 23); + assert.equal(flatten.blue, 21); + assert.equal(flatten.alpha, 1); + + var flattenTwo = axe.commons.color.flattenColors( + colourFour, + colourThree, + 'hard-light' + ); + assert.equal(flattenTwo.red, 201); + assert.equal(flattenTwo.green, 209); + assert.equal(flattenTwo.blue, 90); + assert.equal(flattenTwo.alpha, 1); + }); + + it('should flatten colors correctly using blend mode: soft-light', function() { + var flatten = axe.commons.color.flattenColors( + colourTwo, + colourOne, + 'soft-light' + ); + assert.equal(flatten.red, 215); + assert.equal(flatten.green, 22); + assert.equal(flatten.blue, 21); + assert.equal(flatten.alpha, 1); + + var flattenTwo = axe.commons.color.flattenColors( + colourFour, + colourThree, + 'soft-light' + ); + assert.equal(flattenTwo.red, 209); + assert.equal(flattenTwo.green, 183); + assert.equal(flattenTwo.blue, 154); + assert.equal(flattenTwo.alpha, 1); + }); + + it('should flatten colors correctly using blend mode: difference', function() { + var flatten = axe.commons.color.flattenColors( + colourTwo, + colourOne, + 'difference' + ); + assert.equal(flatten.red, 188); + assert.equal(flatten.green, 43); + assert.equal(flatten.blue, 40); + assert.equal(flatten.alpha, 1); + + var flattenTwo = axe.commons.color.flattenColors( + colourFour, + colourThree, + 'difference' + ); + assert.equal(flattenTwo.red, 154); + assert.equal(flattenTwo.green, 128); + assert.equal(flattenTwo.blue, 180); + assert.equal(flattenTwo.alpha, 1); + }); + + it('should flatten colors correctly using blend mode: exclusion', function() { + var flatten = axe.commons.color.flattenColors( + colourTwo, + colourOne, + 'exclusion' + ); + assert.equal(flatten.red, 196); + assert.equal(flatten.green, 49); + assert.equal(flatten.blue, 46); + assert.equal(flatten.alpha, 1); + + var flattenTwo = axe.commons.color.flattenColors( + colourFour, + colourThree, + 'exclusion' + ); + assert.equal(flattenTwo.red, 173); + assert.equal(flattenTwo.green, 128); + assert.equal(flattenTwo.blue, 180); + assert.equal(flattenTwo.alpha, 1); + }); +}); diff --git a/test/integration/full/contrast/blending.html b/test/integration/full/contrast/blending.html index 2fbc1ad89e..1af0520c50 100644 --- a/test/integration/full/contrast/blending.html +++ b/test/integration/full/contrast/blending.html @@ -22,18 +22,20 @@ margin: 4rem 2rem; } - #fixture { + .test-group { + position: relative; + z-index: 1; display: grid; grid-template-columns: repeat(auto-fit, minmax(200px, 1fr)); } - #fixture > div { + .test-group > div { display: flex; flex-direction: row; border: 1px solid white; } - #fixture * { + .test-group * { width: 100px; height: 100px; flex-shrink: 0; @@ -57,128 +59,131 @@ >

-
-
-
+

normal

+
+
+
+
+
+ Test1 +
+
+
+
Test1 result
+
+ +
+
- Test1 + Test2
+
Test2 result
-
Test1 result
-
-
-
-
- Test2 +
+
+
+ Test3 +
+
Test3 result
-
Test2 result
-
-
-
-
- Test3 +
+
+
+
+ Test4 +
+
+
Test4 result
-
Test3 result
-
-
-
-
+
+
- Test4 + Test5
+
Test5 result
-
Test4 result
-
- -
-
-
- Test5 -
-
-
Test5 result
-
-
-
-
- Test6 +
+
+
+ Test6 +
+
Test6 result
-
Test6 result
-
-
-
+
-
-
- Test7 +
+
+
+ Test7 +
+
Test7 result
-
Test7 result
-
-
-
+
-
-
-
-
- Test8 +
+
+
+
+
+ Test8 +
+
Test8 result
-
Test8 result
-
-
-
-
- Test9 +
+
+
+ Test9 +
+
Test9 result
-
Test9 result
diff --git a/test/integration/full/contrast/blending.js b/test/integration/full/contrast/blending.js index 7d1bde4859..6a006afb5e 100644 --- a/test/integration/full/contrast/blending.js +++ b/test/integration/full/contrast/blending.js @@ -1,18 +1,173 @@ +var isIE11 = axe.testUtils.isIE11; + describe('color-contrast blending test', function() { var include = []; var resultElms = []; var expected = [ + // normal 'rgb(223, 112, 96)', 'rgb(255, 128, 128)', 'rgb(191, 223, 191)', 'rgb(125, 38, 54)', 'rgb(179, 38, 0)', 'rgb(179, 0, 77)', - 'rgb(143, 192, 80)', - 'rgb(147, 153, 119)', - 'rgb(221, 221, 221)' + 'rgb(144, 192, 81)', + 'rgb(147, 154, 120)', + 'rgb(221, 221, 221)', + // multiply + 'rgb(191, 112, 96)', + 'rgb(255, 128, 128)', + 'rgb(191, 223, 191)', + 'rgb(125, 0, 54)', + 'rgb(179, 0, 0)', + 'rgb(179, 0, 0)', + 'rgb(144, 171, 81)', + 'rgb(147, 154, 112)', + 'rgb(213, 213, 213)', + // screen + 'rgb(223, 223, 191)', + 'rgb(255, 255, 255)', + 'rgb(255, 255, 255)', + 'rgb(179, 38, 77)', + 'rgb(255, 38, 0)', + 'rgb(255, 0, 77)', + 'rgb(165, 192, 81)', + 'rgb(150, 157, 120)', + 'rgb(228, 228, 228)', + // overlay + 'rgb(223, 207, 159)', + 'rgb(255, 255, 255)', + 'rgb(255, 255, 255)', + 'rgb(156, 0, 54)', + 'rgb(255, 0, 0)', + 'rgb(255, 0, 0)', + 'rgb(148, 187, 81)', + 'rgb(147, 154, 114)', + 'rgb(226, 226, 226)', + // darken + 'rgb(191, 112, 96)', + 'rgb(255, 128, 128)', + 'rgb(191, 223, 191)', + 'rgb(125, 0, 54)', + 'rgb(179, 0, 0)', + 'rgb(179, 0, 0)', + 'rgb(144, 171, 81)', + 'rgb(147, 154, 112)', + 'rgb(221, 221, 221)', + // lighten + 'rgb(223, 223, 191)', + 'rgb(255, 255, 255)', + 'rgb(255, 255, 255)', + 'rgb(179, 38, 77)', + 'rgb(255, 38, 0)', + 'rgb(255, 0, 77)', + 'rgb(165, 192, 81)', + 'rgb(150, 157, 120)', + 'rgb(221, 221, 221)', + // color-dodge + 'rgb(223, 223, 191)', + 'rgb(255, 255, 255)', + 'rgb(255, 255, 255)', + 'rgb(179, 0, 77)', + 'rgb(255, 0, 0)', + 'rgb(255, 0, 0)', + 'rgb(165, 192, 81)', + 'rgb(150, 157, 120)', + 'rgb(230, 230, 230)', + // color-burn + 'rgb(191, 112, 96)', + 'rgb(255, 255, 255)', + 'rgb(255, 255, 255)', + 'rgb(125, 0, 54)', + 'rgb(255, 0, 0)', + 'rgb(255, 0, 0)', + 'rgb(144, 171, 81)', + 'rgb(147, 154, 112)', + 'rgb(219, 219, 219)', + // hard-light + 'rgb(223, 112, 96)', + 'rgb(255, 128, 128)', + 'rgb(191, 255, 191)', + 'rgb(125, 0, 54)', + 'rgb(179, 0, 0)', + 'rgb(179, 0, 77)', + 'rgb(144, 192, 81)', + 'rgb(147, 154, 120)', + 'rgb(226, 226, 226)', + // soft-light + 'rgb(206, 209, 167)', + 'rgb(255, 255, 255)', + 'rgb(255, 255, 255)', + 'rgb(163, 0, 61)', + 'rgb(255, 0, 0)', + 'rgb(255, 0, 0)', + 'rgb(155, 180, 81)', + 'rgb(148, 155, 115)', + 'rgb(223, 223, 223)', + // difference + 'rgb(128, 223, 191)', + 'rgb(128, 255, 255)', + 'rgb(255, 223, 255)', + 'rgb(179, 38, 77)', + 'rgb(255, 38, 0)', + 'rgb(255, 0, 77)', + 'rgb(165, 176, 81)', + 'rgb(150, 157, 119)', + 'rgb(183, 183, 183)', + // exclusion + 'rgb(128, 223, 191)', + 'rgb(128, 255, 255)', + 'rgb(255, 223, 255)', + 'rgb(179, 38, 77)', + 'rgb(255, 38, 0)', + 'rgb(255, 0, 77)', + 'rgb(165, 176, 81)', + 'rgb(150, 157, 119)', + 'rgb(198, 198, 198)' ]; - var testElms = Array.from(document.querySelectorAll('#fixture > div')); + + var fixture = document.querySelector('#fixture'); + var testGroup = document.querySelector('.test-group'); + [ + 'multiply', + 'screen', + 'overlay', + 'darken', + 'lighten', + 'color-dodge', + 'color-burn', + 'hard-light', + 'soft-light', + 'difference', + 'exclusion' + ].forEach(function(blendMode) { + var nodes = testGroup.cloneNode(true); + var group = testGroup.cloneNode(); + + var heading = document.createElement('h2'); + heading.textContent = blendMode; + fixture.appendChild(heading); + + Array.from(nodes.children).forEach(function(node, index) { + var id = node.id; + var target = node.querySelector('#' + id + '-target'); + var result = node.querySelector('#' + id + '-result'); + var blendModeIndex = blendMode + (index + 1); + + node.id = blendModeIndex; + target.id = blendModeIndex + '-target'; + result.id = blendModeIndex + '-result'; + + target.textContent = blendModeIndex; + result.textContent = blendModeIndex + ' result'; + + target.style.mixBlendMode = blendMode; + group.appendChild(node); + }); + + fixture.appendChild(group); + }); + var testElms = Array.from(document.querySelectorAll('.test-group > div')); testElms.forEach(function(testElm) { var id = testElm.id; var target = testElm.querySelector('#' + id + '-target'); @@ -22,29 +177,38 @@ describe('color-contrast blending test', function() { }); before(function(done) { - axe.run({ include: include }, { runOnly: ['color-contrast'] }, function( - err, - res - ) { - assert.isNull(err); - - // don't care where the result goes as we just want to - // extract the background color for each one - var results = [] - .concat(res.passes) - .concat(res.violations) - .concat(res.incomplete); - results.forEach(function(result) { - result.nodes.forEach(function(node) { - var bgColor = node.any[0].data.bgColor; - var id = node.target[0].split('-')[0]; - var result = document.querySelector(id + '-result'); - result.style.backgroundColor = bgColor; + // mix-blend-mode is not supported on IE11 + // @see https://developer.mozilla.org/en-US/docs/Web/CSS/mix-blend-mode + if (isIE11) { + this.skip(); + } else { + axe.run({ include: include }, { runOnly: ['color-contrast'] }, function( + err, + res + ) { + assert.isNull(err); + + // don't care where the result goes as we just want to + // extract the background color for each one + var results = [] + .concat(res.passes) + .concat(res.violations) + .concat(res.incomplete); + results.forEach(function(result) { + result.nodes.forEach(function(node) { + var bgColor = node.any[0].data.bgColor; + var id = node.target[0].substring( + 0, + node.target[0].lastIndexOf('-') + ); + var result = document.querySelector(id + '-result'); + result.style.backgroundColor = bgColor; + }); }); - }); - done(); - }); + done(); + }); + } }); resultElms.forEach(function(elm, index) {