From b6a5583f372c15909618dde4cb189ef83a01354f Mon Sep 17 00:00:00 2001 From: Yura Zenevich Date: Sun, 16 Dec 2018 13:49:51 +0000 Subject: [PATCH] Bug 1513557 - adding overlapping swatch preview for colour contrast indicator in a11y panel. r=pbro,flod MozReview-Commit-ID: 9IKGXorA6uS Differential Revision: https://phabricator.services.mozilla.com/D14429 --HG-- extra : moz-landing-system : lando --- devtools/server/actors/highlighters.css | 22 ++++++++--- .../highlighters/utils/accessibility.js | 37 +++++++++++++++---- .../actors/highlighters/xul-accessible.js | 24 +++++++++--- devtools/server/actors/utils/accessibility.js | 21 ++++++++--- devtools/shared/css/color.js | 4 ++ .../locales/en-US/accessibility.properties | 5 +++ 6 files changed, 87 insertions(+), 26 deletions(-) diff --git a/devtools/server/actors/highlighters.css b/devtools/server/actors/highlighters.css index 5d6098d03e63..f0b37aa2114c 100644 --- a/devtools/server/actors/highlighters.css +++ b/devtools/server/actors/highlighters.css @@ -37,6 +37,8 @@ --highlighter-font-size: 11px; --highlighter-infobar-color: hsl(210, 30%, 85%); --highlighter-marker-color: #000; + + --grey-40: #b1b1b3; } /** @@ -653,6 +655,17 @@ max-width: 90%; } +:-moz-native-anonymous .accessible-infobar-audit .accessible-contrast-ratio:not(:empty):before { + content: ""; + height: 8px; + width: 8px; + display: inline-flex; + background-color: var(--accessibility-highlighter-contrast-ratio-color); + box-shadow: 0 0 0 1px var(--grey-40), 4px 3px var(--accessibility-highlighter-contrast-ratio-bg), 4px 3px 0 1px var(--grey-40); + margin-inline-start: 3px; + margin-inline-end: 9px; +} + :-moz-native-anonymous .accessible-infobar-audit .accessible-contrast-ratio:not(:empty):after { margin-inline-start: 2px; } @@ -676,16 +689,13 @@ } :-moz-native-anonymous .accessible-infobar-audit .accessible-contrast-ratio-label, -:-moz-native-anonymous .accessible-infobar-audit #accessible-contrast-ratio-max:not(:empty):before { +:-moz-native-anonymous .accessible-infobar-audit .accessible-contrast-ratio-separator:before { margin-inline-end: 3px; } -:-moz-native-anonymous .accessible-infobar-audit #accessible-contrast-ratio-max { - margin-inline-start: 3px; -} - -:-moz-native-anonymous .accessible-infobar-audit #accessible-contrast-ratio-max:not(:empty):before { +:-moz-native-anonymous .accessible-infobar-audit .accessible-contrast-ratio-separator:before { content: "-"; + margin-inline-start: 3px; } :-moz-native-anonymous .accessible-infobar-name:not(:empty), diff --git a/devtools/server/actors/highlighters/utils/accessibility.js b/devtools/server/actors/highlighters/utils/accessibility.js index 0a1b1595abdc..459687c60e79 100644 --- a/devtools/server/actors/highlighters/utils/accessibility.js +++ b/devtools/server/actors/highlighters/utils/accessibility.js @@ -479,14 +479,13 @@ class ContrastRatio extends AuditReport { "id": "contrast-ratio-label", }, prefix: this.prefix, - text: L10N.getStr("accessibility.contrast.ratio.label"), }); createNode(this.win, { nodeType: "span", parent: root, attributes: { - "class": "contrast-ratio", + "class": "contrast-ratio-error", "id": "contrast-ratio-error", }, prefix: this.prefix, @@ -503,6 +502,16 @@ class ContrastRatio extends AuditReport { prefix: this.prefix, }); + createNode(this.win, { + nodeType: "span", + parent: root, + attributes: { + "class": "contrast-ratio-separator", + "id": "contrast-ratio-separator", + }, + prefix: this.prefix, + }); + createNode(this.win, { nodeType: "span", parent: root, @@ -514,11 +523,14 @@ class ContrastRatio extends AuditReport { }); } - _fillAndStyleContrastValue(el, value, isLargeText, stringName) { + _fillAndStyleContrastValue(el, { value, isLargeText, color, backgroundColor }) { value = value.toFixed(2); const style = getContrastRatioScoreStyle(value, isLargeText); - this.setTextContent(el, stringName ? L10N.getFormatStr(stringName, value) : value); + this.setTextContent(el, value); el.classList.add(style); + el.setAttribute("style", + `--accessibility-highlighter-contrast-ratio-color: rgba(${color});` + + `--accessibility-highlighter-contrast-ratio-bg: rgba(${backgroundColor});`); el.removeAttribute("hidden"); } @@ -532,7 +544,7 @@ class ContrastRatio extends AuditReport { */ update({ contrastRatio }) { const els = {}; - for (const key of ["label", "min", "max", "error"]) { + for (const key of ["label", "min", "max", "error", "separator"]) { const el = els[key] = this.getElement(`contrast-ratio-${key}`); if (["min", "max"].includes(key)) { ["fail", "AA", "AAA"].forEach(className => el.classList.remove(className)); @@ -540,6 +552,7 @@ class ContrastRatio extends AuditReport { } el.setAttribute("hidden", true); + el.removeAttribute("style"); } if (!contrastRatio) { @@ -547,6 +560,8 @@ class ContrastRatio extends AuditReport { } const { isLargeText, error } = contrastRatio; + this.setTextContent(els.label, + L10N.getStr(`accessibility.contrast.ratio.label${isLargeText ? ".large" : ""}`)); els.label.removeAttribute("hidden"); if (error) { els.error.removeAttribute("hidden"); @@ -554,12 +569,18 @@ class ContrastRatio extends AuditReport { } if (contrastRatio.value) { - this._fillAndStyleContrastValue(els.min, contrastRatio.value, isLargeText); + const { value, color, backgroundColor } = contrastRatio; + this._fillAndStyleContrastValue(els.min, + { value, isLargeText, color, backgroundColor }); return true; } - this._fillAndStyleContrastValue(els.min, contrastRatio.min, isLargeText); - this._fillAndStyleContrastValue(els.max, contrastRatio.max, isLargeText); + const { min, max, color, backgroundColorMin, backgroundColorMax } = contrastRatio; + this._fillAndStyleContrastValue(els.min, + { value: min, isLargeText, color, backgroundColor: backgroundColorMin }); + els.separator.removeAttribute("hidden"); + this._fillAndStyleContrastValue(els.max, + { value: max, isLargeText, color, backgroundColor: backgroundColorMax }); return true; } diff --git a/devtools/server/actors/highlighters/xul-accessible.js b/devtools/server/actors/highlighters/xul-accessible.js index dd090200802b..828b001644d6 100644 --- a/devtools/server/actors/highlighters/xul-accessible.js +++ b/devtools/server/actors/highlighters/xul-accessible.js @@ -18,6 +18,8 @@ const ACCESSIBLE_BOUNDS_SHEET = "data:text/css;charset=utf-8," + encodeURICompon --highlighter-bubble-background-color: hsl(214, 13%, 24%); --highlighter-bubble-border-color: rgba(255, 255, 255, 0.2); --highlighter-bubble-arrow-size: 8px; + + --grey-40: #b1b1b3; } .accessible-bounds { @@ -79,6 +81,19 @@ const ACCESSIBLE_BOUNDS_SHEET = "data:text/css;charset=utf-8," + encodeURICompon max-width: 90%; } + .accessible-infobar-audit .accessible-contrast-ratio:not(:empty):before { + content: ""; + height: 8px; + width: 8px; + display: inline-flex; + background-color: var(--accessibility-highlighter-contrast-ratio-color); + box-shadow: 0 0 0 1px var(--grey-40), + 4px 3px var(--accessibility-highlighter-contrast-ratio-bg), + 4px 3px 0 1px var(--grey-40); + margin-inline-start: 3px; + margin-inline-end: 9px; + } + .accessible-infobar-audit .accessible-contrast-ratio:not(:empty):after { margin-inline-start: 2px; } @@ -102,16 +117,13 @@ const ACCESSIBLE_BOUNDS_SHEET = "data:text/css;charset=utf-8," + encodeURICompon } .accessible-infobar-audit .accessible-contrast-ratio-label, - .accessible-infobar-audit #accessible-contrast-ratio-max:not(:empty):before { + .accessible-infobar-audit .accessible-contrast-ratio-separator:before { margin-inline-end: 3px; } - .accessible-infobar-audit #accessible-contrast-ratio-max { - margin-inline-start: 3px; - } - - .accessible-infobar-audit #accessible-contrast-ratio-max:not(:empty):before { + .accessible-infobar-audit .accessible-contrast-ratio-separator:before { content: "-"; + margin-inline-start: 3px; } .accessible-infobar-name:not(:empty), diff --git a/devtools/server/actors/utils/accessibility.js b/devtools/server/actors/utils/accessibility.js index 83011c0a1fd6..dc2d40ac8d8c 100644 --- a/devtools/server/actors/utils/accessibility.js +++ b/devtools/server/actors/utils/accessibility.js @@ -196,18 +196,27 @@ function getContrastRatioFor(node, options = {}) { if (rgba.value) { return { value: colorUtils.calculateContrastRatio(rgba.value, color), + color, + backgroundColor: rgba.value, isLargeText, }; } - // calculateContrastRatio modifies the array, since we need to use color array twice, - // pass its copy to the method. - const min = colorUtils.calculateContrastRatio(rgba.min, Array.from(color)); - const max = colorUtils.calculateContrastRatio(rgba.max, Array.from(color)); + let min = colorUtils.calculateContrastRatio(rgba.min, color); + let max = colorUtils.calculateContrastRatio(rgba.max, color); + + // Flip minimum and maximum contrast ratios if necessary. + if (min > max) { + [min, max] = [max, min]; + [rgba.min, rgba.max] = [rgba.max, rgba.min]; + } return { - min: min < max ? min : max, - max: min < max ? max : min, + min, + max, + color, + backgroundColorMin: rgba.min, + backgroundColorMax: rgba.max, isLargeText, }; } diff --git a/devtools/shared/css/color.js b/devtools/shared/css/color.js index 85756460bf18..9d2392babcb3 100644 --- a/devtools/shared/css/color.js +++ b/devtools/shared/css/color.js @@ -1197,6 +1197,10 @@ function blendColors(foregroundColor, backgroundColor = [ 255, 255, 255, 1 ]) { * @return {Number} The calculated luminance. */ function calculateContrastRatio(backgroundColor, textColor) { + // Do not modify given colors. + backgroundColor = Array.from(backgroundColor); + textColor = Array.from(textColor); + backgroundColor = blendColors(backgroundColor); textColor = blendColors(textColor, backgroundColor); diff --git a/devtools/shared/locales/en-US/accessibility.properties b/devtools/shared/locales/en-US/accessibility.properties index 58444eaf1e8f..8131c3997eb9 100644 --- a/devtools/shared/locales/en-US/accessibility.properties +++ b/devtools/shared/locales/en-US/accessibility.properties @@ -14,3 +14,8 @@ accessibility.contrast.ratio.error=Unable to calculate # LOCALIZATION NOTE (accessibility.contrast.ratio.label): A title text for the color # contrast ratio description, used together with the actual values. accessibility.contrast.ratio.label=Contrast: + +# LOCALIZATION NOTE (accessibility.contrast.ratio.label.large): A title text for the color +# contrast ratio description that also specifies that the color contrast criteria used is +# if for large text. +accessibility.contrast.ratio.label.large=Contrast (large text):