Skip to content

Commit 2f9fd0c

Browse files
committed
Issue warnings for alpha in contrast checking.
Three complications with calculating the "flattened" (non-alpha) representation of font color and background color are: * determining what is actually behind the text - elements may be positioned with css such that it's very hard to determine what element is the background of some or all of the text * the css opacity element may introduce further aspects of transparency * transparent background can reveal images where contrast cannot be calculated
1 parent 5f45d32 commit 2f9fd0c

File tree

5 files changed

+40
-104
lines changed

5 files changed

+40
-104
lines changed

HTMLCS.Util.js

Lines changed: 13 additions & 81 deletions
Original file line numberDiff line numberDiff line change
@@ -534,86 +534,9 @@ _global.HTMLCS.util = function() {
534534
}
535535

536536
/**
537-
* Convert an rgba colour to rgb, by traversing the dom and mixing colors as needed.
537+
* Convert a colour string to a structure with red/green/blue/alpha elements.
538538
*
539-
* @param element - the element to compare the rgba color against.
540-
* @param colour - the starting rgba color to check.
541-
* @returns {Colour Object}
542-
*/
543-
self.rgbaBackgroundToRgb = function(colour, element) {
544-
var parent = element.parentNode;
545-
var original = self.colourStrToRGB(colour);
546-
var backgrounds = [];
547-
var solidFound = false;
548-
549-
if (original.alpha == 1) {
550-
//Return early if it is already solid.
551-
return original;
552-
}
553-
554-
//Find all the background with transparancy until we get to a solid colour
555-
while (solidFound == false) {
556-
if ((!parent) || (!parent.ownerDocument)) {
557-
//No parent was found, assume a solid white background.
558-
backgrounds.push({
559-
red: 1,
560-
green: 1,
561-
blue: 1,
562-
alpha: 1
563-
});
564-
break;
565-
}
566-
567-
var parentStyle = self.style(parent);
568-
var parentColourStr = parentStyle.backgroundColor;
569-
var parentColour = self.colourStrToRGB(parentColourStr);
570-
571-
if ((parentColourStr === 'transparent') || (parentColourStr === 'rgba(0, 0, 0, 0)')) {
572-
//Skip totally transparent parents until we find a solid color.
573-
parent = parent.parentNode;
574-
continue;
575-
}
576-
577-
backgrounds.push(parentColour);
578-
579-
if (parentColour.alpha == 1) {
580-
solidFound = true;
581-
}
582-
583-
parent = parent.parentNode;
584-
}
585-
586-
//Now we need to start with the solid color that we found, and work our way up to the original color.
587-
var solidColour = backgrounds.pop();
588-
while (backgrounds.length) {
589-
solidColour = self.mixColours(solidColour, backgrounds.pop());
590-
}
591-
592-
return self.mixColours(solidColour, original);
593-
};
594-
595-
self.mixColours = function(bg, fg) {
596-
//Convert colors to int values for mixing.
597-
bg.red = Math.round(bg.red*255);
598-
bg.green = Math.round(bg.green*255);
599-
bg.blue = Math.round(bg.blue*255);
600-
fg.red = Math.round(fg.red*255);
601-
fg.green = Math.round(fg.green*255);
602-
fg.blue = Math.round(fg.blue*255);
603-
604-
return {
605-
red: Math.round(fg.alpha * fg.red + (1 - fg.alpha) * bg.red) / 255,
606-
green: Math.round(fg.alpha * fg.green + (1 - fg.alpha) * bg.green) / 255,
607-
blue: Math.round(fg.alpha * fg.blue + (1 - fg.alpha) * bg.blue) / 255,
608-
alpha: bg.alpha
609-
}
610-
}
611-
612-
/**
613-
* Convert a colour string to a structure with red/green/blue elements.
614-
*
615-
* Supports rgb() and hex colours (3 or 6 hex digits, optional "#").
616-
* rgba() also supported but the alpha channel is currently ignored.
539+
* Supports rgb() and hex colours (3, 4, 6 or 8 hex digits, optional "#").
617540
* Each red/green/blue element is in the range [0.0, 1.0].
618541
*
619542
* @param {String} colour The colour to convert.
@@ -645,11 +568,20 @@ _global.HTMLCS.util = function() {
645568
colour = colour.replace(/^(.)(.)(.)$/, '$1$1$2$2$3$3');
646569
}
647570

571+
if (colour.length === 4) {
572+
colour = colour.replace(/^(.)(.)(.)(.)$/, '$1$1$2$2$3$3$4$4');
573+
}
574+
575+
var alpha = 1; // Default if alpha is not specified
576+
if (colour.length === 8) {
577+
alpha = parseInt(colour.substr(6, 2), 16) / 255;
578+
}
579+
648580
colour = {
649581
red: (parseInt(colour.substr(0, 2), 16) / 255),
650-
gsreen: (parseInt(colour.substr(2, 2), 16) / 255),
582+
green: (parseInt(colour.substr(2, 2), 16) / 255),
651583
blue: (parseInt(colour.substr(4, 2), 16) / 255),
652-
alpha: 1
584+
alpha: alpha,
653585
};
654586
}
655587

Standards/WCAG2AAA/Sniffs/Principle1/Guideline1_3/1_3_1.js

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -202,7 +202,6 @@ _global.HTMLCS_WCAG2AAA_Sniffs_Principle1_Guideline1_3_1_3_1 = {
202202
testLabelsOnInputs: function(element, top, muteErrors)
203203
{
204204
var nodeName = element.nodeName.toLowerCase();
205-
var style = HTMLCS.util.style(element);
206205
var inputType = nodeName;
207206
if (inputType === 'input') {
208207
if (element.hasAttribute('type') === true) {
@@ -231,10 +230,6 @@ _global.HTMLCS_WCAG2AAA_Sniffs_Principle1_Guideline1_3_1_3_1 = {
231230
if (element.getAttribute('hidden') !== null) {
232231
needsLabel = false;
233232
}
234-
235-
if ('none' === style.display) {
236-
needsLabel = false;
237-
}
238233

239234
// Find an explicit label.
240235
var explicitLabel = element.ownerDocument.querySelector('label[for="' + element.id + '"]');

Standards/WCAG2AAA/Sniffs/Principle1/Guideline1_4/1_4_3_Contrast.js

Lines changed: 25 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ _global.HTMLCS_WCAG2AAA_Sniffs_Principle1_Guideline1_4_1_4_3_Contrast = {
2323
var toProcess = [];
2424
var body = top.getElementsByTagName('body');
2525
if (body.length) {
26-
//SVG objects will not have a body element. Don't check them.
26+
// SVG objects will not have a body element. Don't check them.
2727
var toProcess = [body[0]];
2828
}
2929
} else {
@@ -99,8 +99,8 @@ _global.HTMLCS_WCAG2AAA_Sniffs_Principle1_Guideline1_4_1_4_3_Contrast = {
9999
isAbsolute = true;
100100
}
101101

102-
//Search for the smooth scrolling willChange: 'transform' background hack
103-
//See http://fourkitchens.com/blog/article/fix-scrolling-performance-css-will-change-property
102+
// Search for the smooth scrolling willChange: 'transform' background hack
103+
// See http://fourkitchens.com/blog/article/fix-scrolling-performance-css-will-change-property
104104
var beforeStyle = HTMLCS.util.style(parent, ':before');
105105
if (
106106
beforeStyle
@@ -120,14 +120,28 @@ _global.HTMLCS_WCAG2AAA_Sniffs_Principle1_Guideline1_4_1_4_3_Contrast = {
120120
}//end while
121121

122122
if (bgColour && bgColour.indexOf('rgba') === 0) {
123-
bgColour = HTMLCS.util.RGBtoColourStr(HTMLCS.util.rgbaBackgroundToRgb(bgColour, bgElement));
124-
}
125-
126-
if (foreColour && foreColour.indexOf('rgba') === 0) {
127-
foreColour = HTMLCS.util.RGBtoColourStr(HTMLCS.util.rgbaBackgroundToRgb(foreColour, node));
128-
}
129-
130-
if (hasBgImg === true) {
123+
// If we have a rgba background color, skip the contrast ratio checks,
124+
// and push a warning instead.
125+
failures.push({
126+
element: node,
127+
colour: foreColour,
128+
bgColour: bgColour,
129+
value: undefined,
130+
required: reqRatio
131+
});
132+
continue;
133+
} else if (foreColour && foreColour.indexOf('rgba') === 0) {
134+
// If we have a rgba fore colour, skip the contrast ratio checks,
135+
// and push a warning instead.
136+
failures.push({
137+
element: node,
138+
colour: foreColour,
139+
bgColour: foreColour,
140+
value: undefined,
141+
required: reqRatio
142+
});
143+
continue;
144+
} else if (hasBgImg === true) {
131145
// If we have a background image, skip the contrast ratio checks,
132146
// and push a warning instead.
133147
failures.push({

Standards/WCAG2AAA/Sniffs/Principle4/Guideline4_1/4_1_2.js

Lines changed: 0 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -185,13 +185,6 @@ _global.HTMLCS_WCAG2AAA_Sniffs_Principle4_Guideline4_1_4_1_2 = {
185185
var element = elements[el];
186186
var nodeName = element.nodeName.toLowerCase();
187187
var msgSubCode = element.nodeName.substr(0, 1).toUpperCase() + element.nodeName.substr(1).toLowerCase();
188-
189-
var style = HTMLCS.util.style(element);
190-
if ('none' === style.display) {
191-
//Element is hidden, so no name is required
192-
continue;
193-
}
194-
195188
if (nodeName === 'input') {
196189
if (element.hasAttribute('type') === false) {
197190
// If no type attribute, default to text.

Tests/WCAG2/1_4_3_Contrast.html

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,8 @@
1515

1616
<p>Sample: <span id="issue155" style="color: #7c7cff; background-color: #ffffff; font-size: 14pt; font-weight: bold;">I am 14pt bold text and should pass</span></p>
1717

18+
<p>Warning: <span id="pr134" style="color: #7c7cff; background-color: #0000000C; font-size: 14pt; font-weight: bold;">I am 14pt bold text on a transparent background and should generate a warning</span></p>
19+
1820
</body>
1921
</html>
2022

0 commit comments

Comments
 (0)