Skip to content

Commit 5f45d32

Browse files
mfairchild365phillbaker
authored andcommitted
Add methods to convert an rgba background color to rgb
1 parent 690e26d commit 5f45d32

File tree

4 files changed

+141
-15
lines changed

4 files changed

+141
-15
lines changed

HTMLCS.Util.js

Lines changed: 90 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -191,14 +191,15 @@ _global.HTMLCS.util = function() {
191191
*
192192
* @returns {Object}
193193
*/
194-
self.style = function(element) {
194+
self.style = function(element, pseudo) {
195195
var computedStyle = null;
196196
var window = self.getElementWindow(element);
197+
var pseudo = pseudo || null;
197198

198199
if (element.currentStyle) {
199200
computedStyle = element.currentStyle;
200201
} else if (window.getComputedStyle) {
201-
computedStyle = window.getComputedStyle(element, null);
202+
computedStyle = window.getComputedStyle(element, pseudo);
202203
}
203204

204205
return computedStyle;
@@ -240,7 +241,7 @@ _global.HTMLCS.util = function() {
240241
* Returns true if the element is deliberately hidden from Accessibility APIs using ARIA hidden.
241242
*
242243
* Not: This is separate to isAccessibilityHidden() due to a need to check specifically for aria hidden.
243-
*
244+
*
244245
* @param {Node} element The element to check.
245246
*
246247
* @return {Boolean}
@@ -397,7 +398,7 @@ _global.HTMLCS.util = function() {
397398
* Returns all elements that are visible to the accessibility API.
398399
*
399400
* @param {Node} element The parent element to search.
400-
* @param {String} selector Optional selector to pass to
401+
* @param {String} selector Optional selector to pass to
401402
*
402403
* @return {Array}
403404
*/
@@ -532,6 +533,82 @@ _global.HTMLCS.util = function() {
532533
return lum;
533534
}
534535

536+
/**
537+
* Convert an rgba colour to rgb, by traversing the dom and mixing colors as needed.
538+
*
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+
535612
/**
536613
* Convert a colour string to a structure with red/green/blue elements.
537614
*
@@ -552,7 +629,11 @@ _global.HTMLCS.util = function() {
552629
colour = {
553630
red: (matches[1] / 255),
554631
green: (matches[2] / 255),
555-
blue: (matches[3] / 255)
632+
blue: (matches[3] / 255),
633+
alpha: 1.0
634+
};
635+
if (matches[4]) {
636+
colour.alpha = parseFloat(/^,\s*(.*)$/.exec(matches[4])[1]);
556637
}
557638
} else {
558639
// Hex digit format.
@@ -566,8 +647,9 @@ _global.HTMLCS.util = function() {
566647

567648
colour = {
568649
red: (parseInt(colour.substr(0, 2), 16) / 255),
569-
green: (parseInt(colour.substr(2, 2), 16) / 255),
570-
blue: (parseInt(colour.substr(4, 2), 16) / 255)
650+
gsreen: (parseInt(colour.substr(2, 2), 16) / 255),
651+
blue: (parseInt(colour.substr(4, 2), 16) / 255),
652+
alpha: 1
571653
};
572654
}
573655

@@ -1290,4 +1372,4 @@ _global.HTMLCS.util = function() {
12901372
};
12911373

12921374
return self;
1293-
}();
1375+
}();

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

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -202,6 +202,7 @@ _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);
205206
var inputType = nodeName;
206207
if (inputType === 'input') {
207208
if (element.hasAttribute('type') === true) {
@@ -230,6 +231,10 @@ _global.HTMLCS_WCAG2AAA_Sniffs_Principle1_Guideline1_3_1_3_1 = {
230231
if (element.getAttribute('hidden') !== null) {
231232
needsLabel = false;
232233
}
234+
235+
if ('none' === style.display) {
236+
needsLabel = false;
237+
}
233238

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

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

Lines changed: 39 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,12 @@ _global.HTMLCS_WCAG2AAA_Sniffs_Principle1_Guideline1_4_1_4_3_Contrast = {
2020
var failures = [];
2121

2222
if (!top.ownerDocument) {
23-
var toProcess = [top.getElementsByTagName('body')[0]];
23+
var toProcess = [];
24+
var body = top.getElementsByTagName('body');
25+
if (body.length) {
26+
//SVG objects will not have a body element. Don't check them.
27+
var toProcess = [body[0]];
28+
}
2429
} else {
2530
var toProcess = [top];
2631
}
@@ -52,11 +57,11 @@ _global.HTMLCS_WCAG2AAA_Sniffs_Principle1_Guideline1_4_1_4_3_Contrast = {
5257
var bgElement = node;
5358
var hasBgImg = false;
5459
var isAbsolute = false;
55-
56-
if (style.backgroundImage !== 'none') {
60+
61+
if (style.backgroundImage !== 'none') {
5762
hasBgImg = true;
5863
}
59-
64+
6065
if (style.position == 'absolute') {
6166
isAbsolute = true;
6267
}
@@ -86,22 +91,48 @@ _global.HTMLCS_WCAG2AAA_Sniffs_Principle1_Guideline1_4_1_4_3_Contrast = {
8691

8792
var parentStyle = HTMLCS.util.style(parent);
8893
var bgColour = parentStyle.backgroundColor;
94+
var bgElement = parent;
8995
if (parentStyle.backgroundImage !== 'none') {
9096
hasBgImg = true;
9197
}
9298
if (parentStyle.position == 'absolute') {
9399
isAbsolute = true;
94100
}
95101

102+
//Search for the smooth scrolling willChange: 'transform' background hack
103+
//See http://fourkitchens.com/blog/article/fix-scrolling-performance-css-will-change-property
104+
var beforeStyle = HTMLCS.util.style(parent, ':before');
105+
if (
106+
beforeStyle
107+
&& beforeStyle.position == 'fixed'
108+
&& beforeStyle.willChange == 'transform'
109+
//Make sure it is trying to cover the entire content area
110+
&& beforeStyle.width == parentStyle.width
111+
&& parseInt(beforeStyle.height, 10) <= parseInt(parentStyle.height, 10)
112+
//And finally it needs a background image
113+
&& beforeStyle.backgroundImage !== 'none'
114+
) {
115+
hasBgImg = true;
116+
break;
117+
}
118+
96119
parent = parent.parentNode;
97120
}//end while
98121

122+
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+
99130
if (hasBgImg === true) {
100131
// If we have a background image, skip the contrast ratio checks,
101132
// and push a warning instead.
102133
failures.push({
103134
element: node,
104-
colour: style.color,
135+
colour: foreColour,
105136
bgColour: undefined,
106137
value: undefined,
107138
required: reqRatio,
@@ -125,9 +156,10 @@ _global.HTMLCS_WCAG2AAA_Sniffs_Principle1_Guideline1_4_1_4_3_Contrast = {
125156
continue;
126157
}
127158

128-
var contrastRatio = HTMLCS.util.contrastRatio(bgColour, style.color);
159+
var contrastRatio = HTMLCS.util.contrastRatio(bgColour, foreColour);
160+
129161
if (contrastRatio < reqRatio) {
130-
var recommendation = this.recommendColour(bgColour, style.color, reqRatio);
162+
var recommendation = this.recommendColour(bgColour, foreColour, reqRatio);
131163

132164
failures.push({
133165
element: node,

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

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -185,6 +185,13 @@ _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+
188195
if (nodeName === 'input') {
189196
if (element.hasAttribute('type') === false) {
190197
// If no type attribute, default to text.

0 commit comments

Comments
 (0)