diff --git a/HTMLCS.js b/HTMLCS.js
index 708229e7..00574742 100755
--- a/HTMLCS.js
+++ b/HTMLCS.js
@@ -851,6 +851,82 @@ var HTMLCS = new function()
return lum;
}
+ /**
+ * Convert an rgba colour to rgb, by traversing the dom and mixing colors as needed.
+ *
+ * @param element - the element to compare the rgba color against.
+ * @param colour - the starting rgba color to check.
+ * @returns {Colour Object}
+ */
+ this.rgbaBackgroundToRgb = function(colour, element) {
+ var parent = element.parentNode;
+ var original = this.colourStrToRGB(colour);
+ var backgrounds = [];
+ var solidFound = false;
+
+ if (original.alpha == 1) {
+ //Return early if it is already solid.
+ return original;
+ }
+
+ //Find all the background with transparancy until we get to a solid colour
+ while (solidFound == false) {
+ if ((!parent) || (!parent.ownerDocument)) {
+ //No parent was found, assume a solid white background.
+ backgrounds.push({
+ red: 1,
+ green: 1,
+ blue: 1,
+ alpha: 1
+ });
+ break;
+ }
+
+ var parentStyle = this.style(parent);
+ var parentColourStr = parentStyle.backgroundColor;
+ var parentColour = this.colourStrToRGB(parentColourStr);
+
+ if ((parentColourStr === 'transparent') || (parentColourStr === 'rgba(0, 0, 0, 0)')) {
+ //Skip totally transparent parents until we find a solid color.
+ parent = parent.parentNode;
+ continue;
+ }
+
+ backgrounds.push(parentColour);
+
+ if (parentColour.alpha == 1) {
+ solidFound = true;
+ }
+
+ parent = parent.parentNode;
+ }
+
+ //Now we need to start with the solid color that we found, and work our way up to the original color.
+ var solidColour = backgrounds.pop();
+ while (backgrounds.length) {
+ solidColour = this.mixColours(solidColour, backgrounds.pop());
+ }
+
+ return this.mixColours(solidColour, original);
+ }
+
+ this.mixColours = function(bg, fg) {
+ //Convert colors to int values for mixing.
+ bg.red = Math.round(bg.red*255);
+ bg.green = Math.round(bg.green*255);
+ bg.blue = Math.round(bg.blue*255);
+ fg.red = Math.round(fg.red*255);
+ fg.green = Math.round(fg.green*255);
+ fg.blue = Math.round(fg.blue*255);
+
+ return {
+ red: Math.round(fg.alpha * fg.red + (1 - fg.alpha) * bg.red) / 255,
+ green: Math.round(fg.alpha * fg.green + (1 - fg.alpha) * bg.green) / 255,
+ blue: Math.round(fg.alpha * fg.blue + (1 - fg.alpha) * bg.blue) / 255,
+ alpha: bg.alpha
+ }
+ }
+
/**
* Convert a colour string to a structure with red/green/blue elements.
*
@@ -871,7 +947,11 @@ var HTMLCS = new function()
colour = {
red: (matches[1] / 255),
green: (matches[2] / 255),
- blue: (matches[3] / 255)
+ blue: (matches[3] / 255),
+ alpha: 1
+ }
+ if (matches[4]) {
+ colour.alpha = parseFloat(/^,\s*(.*)$/.exec(matches[4])[1]);
}
} else {
// Hex digit format.
@@ -886,7 +966,8 @@ var HTMLCS = new function()
colour = {
red: (parseInt(colour.substr(0, 2), 16) / 255),
green: (parseInt(colour.substr(2, 2), 16) / 255),
- blue: (parseInt(colour.substr(4, 2), 16) / 255)
+ blue: (parseInt(colour.substr(4, 2), 16) / 255),
+ alpha: 1
};
}
diff --git a/Standards/WCAG2AAA/Sniffs/Principle1/Guideline1_4/1_4_3.js b/Standards/WCAG2AAA/Sniffs/Principle1/Guideline1_4/1_4_3.js
index 98685e92..6420e313 100644
--- a/Standards/WCAG2AAA/Sniffs/Principle1/Guideline1_4/1_4_3.js
+++ b/Standards/WCAG2AAA/Sniffs/Principle1/Guideline1_4/1_4_3.js
@@ -77,6 +77,9 @@ var HTMLCS_WCAG2AAA_Sniffs_Principle1_Guideline1_4_1_4_3 = {
if (isAbsolute === true) {
code += '.Abs';
HTMLCS.addMessage(HTMLCS.WARNING, element, 'This element is absolutely positioned and the background color can not be determined. Ensure the contrast ratio between the text and all covered parts of the background are at least ' + required + ':1.', code);
+ } else if (bgColour && bgColour.indexOf('rgba') === 0) {
+ code += '.Alpha';
+ HTMLCS.addMessage(HTMLCS.WARNING, element, 'This element\'s text is placed on a background that has an alpha transparency. Ensure the contrast ratio between the text and background color are at least ' + required + ':1.', code);
} else if (hasBgImg === true) {
code += '.BgImage';
HTMLCS.addMessage(HTMLCS.WARNING, element, 'This element\'s text is placed on a background image. Ensure the contrast ratio between the text and all covered parts of the image are at least ' + required + ':1.', code);
diff --git a/Standards/WCAG2AAA/Sniffs/Principle1/Guideline1_4/1_4_3_Contrast.js b/Standards/WCAG2AAA/Sniffs/Principle1/Guideline1_4/1_4_3_Contrast.js
index 51e71054..35f3dbd0 100644
--- a/Standards/WCAG2AAA/Sniffs/Principle1/Guideline1_4/1_4_3_Contrast.js
+++ b/Standards/WCAG2AAA/Sniffs/Principle1/Guideline1_4/1_4_3_Contrast.js
@@ -52,8 +52,8 @@ var HTMLCS_WCAG2AAA_Sniffs_Principle1_Guideline1_4_1_4_3_Contrast = {
var bgElement = node;
var hasBgImg = false;
var isAbsolute = false;
-
- if (style.backgroundImage !== 'none') {
+
+ if (style.backgroundImage !== 'none') {
hasBgImg = true;
}
@@ -86,6 +86,7 @@ var HTMLCS_WCAG2AAA_Sniffs_Principle1_Guideline1_4_1_4_3_Contrast = {
var parentStyle = HTMLCS.util.style(parent);
var bgColour = parentStyle.backgroundColor;
+ var bgElement = parent;
if (parentStyle.backgroundImage !== 'none') {
hasBgImg = true;
}
@@ -96,12 +97,20 @@ var HTMLCS_WCAG2AAA_Sniffs_Principle1_Guideline1_4_1_4_3_Contrast = {
parent = parent.parentNode;
}//end while
+ if (bgColour && bgColour.indexOf('rgba') === 0) {
+ bgColour = HTMLCS.util.RGBtoColourStr(HTMLCS.util.rgbaBackgroundToRgb(bgColour, bgElement));
+ }
+
+ if (foreColour && foreColour.indexOf('rgba') === 0) {
+ foreColour = HTMLCS.util.RGBtoColourStr(HTMLCS.util.rgbaBackgroundToRgb(foreColour, node));
+ }
+
if (hasBgImg === true) {
// If we have a background image, skip the contrast ratio checks,
// and push a warning instead.
failures.push({
element: node,
- colour: style.color,
+ colour: foreColour,
bgColour: undefined,
value: undefined,
required: reqRatio,
@@ -117,6 +126,7 @@ var HTMLCS_WCAG2AAA_Sniffs_Principle1_Guideline1_4_1_4_3_Contrast = {
required: reqRatio,
isAbsolute: true
});
+ continue;
} else if ((bgColour === 'transparent') || (bgColour === 'rgba(0, 0, 0, 0)')) {
// If the background colour is still transparent, this is probably
// a fragment with which we cannot reliably make a statement about
@@ -124,12 +134,12 @@ var HTMLCS_WCAG2AAA_Sniffs_Principle1_Guideline1_4_1_4_3_Contrast = {
continue;
}
- var contrastRatio = HTMLCS.util.contrastRatio(bgColour, style.color);
+ var contrastRatio = HTMLCS.util.contrastRatio(bgColour, foreColour);
if (contrastRatio < reqRatio) {
- var recommendation = this.recommendColour(bgColour, style.color, reqRatio);
+ var recommendation = this.recommendColour(bgColour, foreColour, reqRatio);
failures.push({
element: node,