UNPKG

axe-core

Version:

Accessibility engine for automated Web UI testing

164 lines (142 loc) 4.71 kB
/* global color */ /** * @class Color * @memberof axe.commons.color * @param {number} red * @param {number} green * @param {number} blue * @param {number} alpha */ color.Color = function (red, green, blue, alpha) { /** @type {number} */ this.red = red; /** @type {number} */ this.green = green; /** @type {number} */ this.blue = blue; /** @type {number} */ this.alpha = alpha; /** * Provide the hex string value for the color * @method toHexString * @memberof axe.commons.color.Color * @instance * @return {string} */ this.toHexString = function () { var redString = Math.round(this.red).toString(16); var greenString = Math.round(this.green).toString(16); var blueString = Math.round(this.blue).toString(16); return '#' + (this.red > 15.5 ? redString : '0' + redString) + (this.green > 15.5 ? greenString : '0' + greenString) + (this.blue > 15.5 ? blueString : '0' + blueString); }; var rgbRegex = /^rgb\((\d+), (\d+), (\d+)\)$/; var rgbaRegex = /^rgba\((\d+), (\d+), (\d+), (\d*(\.\d+)?)\)/; /** * Set the color value based on a CSS RGB/RGBA string * @method parseRgbString * @memberof axe.commons.color.Color * @instance * @param {string} rgb The string value */ this.parseRgbString = function (colorString) { // IE can pass transparent as value instead of rgba if (colorString === 'transparent') { this.red = 0; this.green = 0; this.blue = 0; this.alpha = 0; return; } var match = colorString.match(rgbRegex); if (match) { this.red = parseInt(match[1], 10); this.green = parseInt(match[2], 10); this.blue = parseInt(match[3], 10); this.alpha = 1; return; } match = colorString.match(rgbaRegex); if (match) { this.red = parseInt(match[1], 10); this.green = parseInt(match[2], 10); this.blue = parseInt(match[3], 10); this.alpha = parseFloat(match[4]); return; } }; /** * Get the relative luminance value * using algorithm from http://www.w3.org/WAI/GL/wiki/Relative_luminance * @method getRelativeLuminance * @memberof axe.commons.color.Color * @instance * @return {number} The luminance value, ranges from 0 to 1 */ this.getRelativeLuminance = function () { var rSRGB = this.red / 255; var gSRGB = this.green / 255; var bSRGB = this.blue / 255; var r = rSRGB <= 0.03928 ? rSRGB / 12.92 : Math.pow(((rSRGB + 0.055) / 1.055), 2.4); var g = gSRGB <= 0.03928 ? gSRGB / 12.92 : Math.pow(((gSRGB + 0.055) / 1.055), 2.4); var b = bSRGB <= 0.03928 ? bSRGB / 12.92 : Math.pow(((bSRGB + 0.055) / 1.055), 2.4); return 0.2126 * r + 0.7152 * g + 0.0722 * b; }; }; /** * Combine the two given color according to alpha blending. * @method flattenColors * @memberof axe.commons.color.Color * @instance * @param {Color} fgColor Foreground color * @param {Color} bgColor Background color * @return {Color} Blended color */ color.flattenColors = function (fgColor, bgColor) { var alpha = fgColor.alpha; var r = ((1 - alpha) * bgColor.red) + (alpha * fgColor.red); var g = ((1 - alpha) * bgColor.green) + (alpha * fgColor.green); var b = ((1 - alpha) * bgColor.blue) + (alpha * fgColor.blue); var a = fgColor.alpha + (bgColor.alpha * (1 - fgColor.alpha)); return new color.Color(r, g, b, a); }; /** * Get the contrast of two colors * @method getContrast * @memberof axe.commons.color.Color * @instance * @param {Color} bgcolor Background color * @param {Color} fgcolor Foreground color * @return {number} The contrast ratio */ color.getContrast = function (bgColor, fgColor) { if (!fgColor || !bgColor) { return null; } if (fgColor.alpha < 1) { fgColor = color.flattenColors(fgColor, bgColor); } var bL = bgColor.getRelativeLuminance(); var fL = fgColor.getRelativeLuminance(); return (Math.max(fL, bL) + 0.05) / (Math.min(fL, bL) + 0.05); }; /** * Check whether certain text properties meet WCAG contrast rules * @method hasValidContrastRatio * @memberof axe.commons.color.Color * @instance * @param {Color} bgcolor Background color * @param {Color} fgcolor Foreground color * @param {number} fontSize Font size of text, in pixels * @param {boolean} isBold Whether the text is bold * @return {{isValid: boolean, contrastRatio: number, expectedContrastRatio: number}} */ color.hasValidContrastRatio = function (bg, fg, fontSize, isBold) { var contrast = color.getContrast(bg, fg); var isSmallFont = (isBold && (Math.ceil(fontSize * 72) / 96) < 14) || (!isBold && (Math.ceil(fontSize * 72) / 96) < 18); var expectedContrastRatio = isSmallFont ? 4.5 : 3; return { isValid: contrast > expectedContrastRatio, contrastRatio: contrast, expectedContrastRatio: expectedContrastRatio }; };