Skip to content

Commit

Permalink
Merge pull request #1888 from IBMa/dev-1735
Browse files Browse the repository at this point in the history
fixrule(`text_contrast_sufficient`): Support CJK large scale text in color contrast calculation
  • Loading branch information
ErickRenteria authored Apr 12, 2024
2 parents c19b837 + 895dbbd commit be994c6
Show file tree
Hide file tree
Showing 41 changed files with 757 additions and 174 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -17,40 +17,41 @@ import { ColorUtil } from "../../v2/dom/ColorUtil";
import { Rule, RuleResult, RuleFail, RuleContext, RulePotential, RulePass, RuleContextHierarchy } from "../api/IRule";
import { eRulePolicy, eToolkitLevel } from "../api/IRule";
//import { setCache } from "../util/CacheUtil";
import { getWeightNumber, getFontInPixels } from "../util/CSSUtil";
import { getWeightNumber, getFontInPixels} from "../util/CSSUtil";
import { containsCKJ } from "../util/CommonUtil";

export let text_contrast_sufficient: Rule = {
id: "text_contrast_sufficient",
context: "dom:*",
refactor: {
"IBMA_Color_Contrast_WCAG2AA": {
"Pass_0": "Pass_0",
"Fail_1": "Fail_1",
"Potential_1": "Potential_same_color"
"Pass_0": "pass",
"Fail_1": "fail_contrast",
"Potential_1": "potential_same_color"
},
"IBMA_Color_Contrast_WCAG2AA_PV": {
"Pass_0": "Pass_0",
"Potential_1": "Potential_graphic_background"
"pass_0": "pass",
"potential_1": "potential_graphic_background"
}
},
help: {
"en-US": {
"group": `text_contrast_sufficient.html`,
"Pass_0": `text_contrast_sufficient.html`,
"Fail_1": `text_contrast_sufficient.html`,
"Potential_same_color": `text_contrast_sufficient.html`,
"Potential_graphic_background": `text_contrast_sufficient.html`,
"Potential_text_shadow": `text_contrast_sufficient.html`
"pass": `text_contrast_sufficient.html`,
"fail_contrast": `text_contrast_sufficient.html`,
"potential_same_color": `text_contrast_sufficient.html`,
"potential_graphic_background": `text_contrast_sufficient.html`,
"potential_text_shadow": `text_contrast_sufficient.html`
}
},
messages: {
"en-US": {
"group": "The contrast ratio of text with its background must meet WCAG AA requirements",
"Pass_0": "Rule Passed",
"Fail_1": "Text contrast of {0} with its background is less than the WCAG AA minimum requirements for text of size {1}px and weight of {2}",
"Potential_same_color": "The foreground text and its background color are both detected as {3}. Verify the text meets the WCAG AA requirements for minimum contrast",
"Potential_graphic_background": "Verify the contrast ratio of the text against the lightest and the darkest colors of the background meets the WCAG AA minimum requirements for text of size {1}px and weight of {2}",
"Potential_text_shadow": "Verify the contrast ratio of the text with shadow meets the WCAG AA minimum requirements for text of size {1}px and weight of {2}"
"pass": "The contrast ratio of text with its background meets WCAG AA requirements",
"fail_contrast": "Text contrast of {0} with its background is less than the WCAG AA minimum requirements for text of size {1}px and weight of {2}",
"potential_same_color": "The foreground text and its background color are both detected as {3}. Verify the text meets the WCAG AA requirements for minimum contrast",
"potential_graphic_background": "Verify the contrast ratio of the text against the lightest and the darkest colors of the background meets the WCAG AA minimum requirements for text of size {1}px and weight of {2}",
"potential_text_shadow": "Verify the contrast ratio of the text with shadow meets the WCAG AA minimum requirements for text of size {1}px and weight of {2}"
}
},
rulesets: [{
Expand Down Expand Up @@ -104,9 +105,10 @@ export let text_contrast_sufficient: Rule = {
* see https://stackoverflow.com/questions/3770117/what-is-the-range-of-unicode-printable-characters
* (3) for now not consider unicode special characters that are different in different languages
*/
let regex = /[^(a-zA-Z\d\s)\u0000-\u0008\u000B-\u001F\u007F-\u009F\u2000-\u200F\u2028-\u202F\u205F-\u206F\u3000\uFEFF]+/g;
const removed = childStr.trim().replace(regex, '');
if (removed.trim().length === 0)
//let regex = /[^(a-zA-Z\d\s)\u0000-\u0008\u000B-\u001F\u007F-\u009F\u2000-\u200F\u2028-\u202F\u205F-\u206F\u3000\uFEFF]+/g;
let regex = /[^(a-zA-Z\d\s)\^(\u4e00-\u9fff\u3400-\u4dbf)\u0000-\u0008\u000B-\u001F\u007F-\u009F\u2000-\u200F\u2028-\u202F\u205F-\u206F\u3000\uFEFF]+/g;
childStr = childStr.trim().replace(regex, '');
if (childStr.trim().length === 0)
return null;
}

Expand Down Expand Up @@ -252,6 +254,12 @@ export let text_contrast_sufficient: Rule = {
let weight = getWeightNumber(style.fontWeight);
let size = getFontInPixels(style.fontSize, elem);
let isLargeScale = size >= 24 || size >= 18.6 && weight >= 700;

if (containsCKJ(childStr)) {
// https://github.com/act-rules/act-rules.github.io/pull/2121/files
// for CJK, 22 pt or 18 pt with font-weight >= 700, 1pt = 1.333 px
isLargeScale = size >= 29.3 || size >= 24 && weight >= 700;
}
let passed = ratio >= 4.5 || (ratio >= 3 && isLargeScale);
let hasBackground = colorCombo.hasBGImage || colorCombo.hasGradient;
let textShadow = colorCombo.textShadow;
Expand Down Expand Up @@ -287,19 +295,19 @@ export let text_contrast_sufficient: Rule = {
if (!passed) {
if (hasBackground) {
// fire potential since a text on an image or gradient may be still viewable, depending on the text location on the gradient or image
return RulePotential("Potential_graphic_background", [ratio.toFixed(2), size, weight]);;
return RulePotential("potential_graphic_background", [ratio.toFixed(2), size, weight]);;
} else if (textShadow) {
// fire potential since a text with shadow may be still viewable, depending on the shadow efffects
return RulePotential("Potential_text_shadow", [ratio.toFixed(2), size, weight]);;
return RulePotential("potential_text_shadow", [ratio.toFixed(2), size, weight]);;
} else {
if (fg.toHex() === bg.toHex()) {
return RulePotential("Potential_same_color", [ratio.toFixed(2), size, weight, fg.toHex(), bg.toHex(), colorCombo.hasBGImage, colorCombo.hasGradient]);
return RulePotential("potential_same_color", [ratio.toFixed(2), size, weight, fg.toHex(), bg.toHex(), colorCombo.hasBGImage, colorCombo.hasGradient]);
} else {
return RuleFail("Fail_1", [ratio.toFixed(2), size, weight, fg.toHex(), bg.toHex(), colorCombo.hasBGImage, colorCombo.hasGradient]);
return RuleFail("fail_contrast", [ratio.toFixed(2), size, weight, fg.toHex(), bg.toHex(), colorCombo.hasBGImage, colorCombo.hasGradient]);
}
}
} else {
return RulePass("Pass_0", [ratio.toFixed(2), size, weight, fg.toHex(), bg.toHex(), colorCombo.hasBGImage, colorCombo.hasGradient]);
return RulePass("pass", [ratio.toFixed(2), size, weight, fg.toHex(), bg.toHex(), colorCombo.hasBGImage, colorCombo.hasGradient]);
}
}
}
17 changes: 17 additions & 0 deletions accessibility-checker-engine/src/v4/util/CommonUtil.ts
Original file line number Diff line number Diff line change
Expand Up @@ -219,3 +219,20 @@ export function getDeprecatedAriaAttributes(element: Element) {
}
return ret;
}

/*
* string contains CJK (chinese, japaneses, or korea)
* return: boolean
*/
export function containsCKJ(text: string) {
if (!text) return false;

// https://en.wikipedia.org/wiki/CJK_Unified_Ideographs https://ayaka.shn.hk/hanregex/
let regex =/(?:[\u4e00-\u9fff\u3400-\u4dbf])+/g;

const replaced = text.trim().replace(regex, '');
if (replaced.length === text.trim().length)
return false;

return true;
}
Original file line number Diff line number Diff line change
Expand Up @@ -106,8 +106,8 @@ <h1>Test page</h1>
"dom": "/html[1]/body[1]/main[1]/h1[1]",
"aria": "/document[1]/main[1]/heading[1]"
},
"reasonId": "Pass_0",
"message": "Rule Passed",
"reasonId": "pass",
"message": "The contrast ratio of text with its background meets WCAG AA requirements",
"messageArgs": [
"21.00",
32,
Expand All @@ -130,7 +130,7 @@ <h1>Test page</h1>
"dom": "/html[1]/body[1]/main[1]/div[1]/div[1]",
"aria": "/document[1]/main[1]"
},
"reasonId": "Fail_1",
"reasonId": "fail_contrast",
"message": "Text contrast of 2.85 with its background is less than the WCAG AA minimum requirements for text of size 16px and weight of 400",
"messageArgs": [
"2.85",
Expand All @@ -154,7 +154,7 @@ <h1>Test page</h1>
"dom": "/html[1]/body[1]/main[1]/div[1]/div[3]",
"aria": "/document[1]/main[1]"
},
"reasonId": "Fail_1",
"reasonId": "fail_contrast",
"message": "Text contrast of 2.85 with its background is less than the WCAG AA minimum requirements for text of size 16px and weight of 400",
"messageArgs": [
"2.85",
Expand All @@ -178,7 +178,7 @@ <h1>Test page</h1>
"dom": "/html[1]/body[1]/main[1]/div[1]/div[6]",
"aria": "/document[1]/main[1]"
},
"reasonId": "Fail_1",
"reasonId": "fail_contrast",
"message": "Text contrast of 2.85 with its background is less than the WCAG AA minimum requirements for text of size 16px and weight of 400",
"messageArgs": [
"2.85",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6775,8 +6775,8 @@
"dom": "/html[1]/body[1]/div[1]/div[1]/div[1]/section[1]/div[1]/div[1]/article[1]/div[1]/div[1]/div[1]",
"aria": "/document[1]/article[1]"
},
"reasonId": "Pass_0",
"message": "Rule Passed",
"reasonId": "pass",
"message": "The contrast ratio of text with its background meets WCAG AA requirements",
"messageArgs": [
"5.33",
12,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -89,8 +89,8 @@ <h3>Color using Class Tests</h3>
"dom": "/html[1]/body[1]/h3[1]",
"aria": "/document[1]/heading[1]"
},
"reasonId": "Pass_0",
"message": "Rule Passed",
"reasonId": "pass",
"message": "The contrast ratio of text with its background meets WCAG AA requirements",
"messageArgs": [
"21.00",
18.72,
Expand All @@ -113,8 +113,8 @@ <h3>Color using Class Tests</h3>
"dom": "/html[1]/body[1]/div[1]/div[1]",
"aria": "/document[1]"
},
"reasonId": "Pass_0",
"message": "Rule Passed",
"reasonId": "pass",
"message": "The contrast ratio of text with its background meets WCAG AA requirements",
"messageArgs": [
"8.59",
16,
Expand All @@ -137,7 +137,7 @@ <h3>Color using Class Tests</h3>
"dom": "/html[1]/body[1]/div[2]/div[1]",
"aria": "/document[1]"
},
"reasonId": "Fail_1",
"reasonId": "fail_contrast",
"message": "Text contrast of 1.13 with its background is less than the WCAG AA minimum requirements for text of size 16px and weight of 400",
"messageArgs": [
"1.13",
Expand All @@ -161,7 +161,7 @@ <h3>Color using Class Tests</h3>
"dom": "/html[1]/body[1]/div[3]/div[1]",
"aria": "/document[1]"
},
"reasonId": "Fail_1",
"reasonId": "fail_contrast",
"message": "Text contrast of 2.49 with its background is less than the WCAG AA minimum requirements for text of size 16px and weight of 400",
"messageArgs": [
"2.49",
Expand All @@ -185,7 +185,7 @@ <h3>Color using Class Tests</h3>
"dom": "/html[1]/body[1]/div[4]/div[1]/div[1]",
"aria": "/document[1]"
},
"reasonId": "Fail_1",
"reasonId": "fail_contrast",
"message": "Text contrast of 1.13 with its background is less than the WCAG AA minimum requirements for text of size 16px and weight of 400",
"messageArgs": [
"1.13",
Expand All @@ -209,7 +209,7 @@ <h3>Color using Class Tests</h3>
"dom": "/html[1]/body[1]/div[5]/div[1]",
"aria": "/document[1]"
},
"reasonId": "Fail_1",
"reasonId": "fail_contrast",
"message": "Text contrast of 2.49 with its background is less than the WCAG AA minimum requirements for text of size 16px and weight of 400",
"messageArgs": [
"2.49",
Expand All @@ -233,8 +233,8 @@ <h3>Color using Class Tests</h3>
"dom": "/html[1]/body[1]/div[6]/div[1]/div[1]",
"aria": "/document[1]"
},
"reasonId": "Pass_0",
"message": "Rule Passed",
"reasonId": "pass",
"message": "The contrast ratio of text with its background meets WCAG AA requirements",
"messageArgs": [
"5.25",
16,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,8 +36,8 @@
"dom": "/html[1]/body[1]/main[1]",
"aria": "/document[1]/main[1]"
},
"reasonId": "Pass_0",
"message": "Rule Passed",
"reasonId": "pass",
"message": "The contrast ratio of text with its background meets WCAG AA requirements",
"messageArgs": [
"21.00",
16,
Expand All @@ -60,8 +60,8 @@
"dom": "/html[1]/body[1]/main[1]/div[1]/div[1]/#document-fragment[1]/div[1]",
"aria": "/document[1]/main[1]"
},
"reasonId": "Pass_0",
"message": "Rule Passed",
"reasonId": "pass",
"message": "The contrast ratio of text with its background meets WCAG AA requirements",
"messageArgs": [
"15.61",
16,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@
"dom": "/html[1]/body[1]/p[1]",
"aria": "/document[1]/paragraph[1]"
},
"reasonId": "Fail_1",
"reasonId": "fail_contrast",
"message": "Text contrast of 2.32 with its background is less than the WCAG AA minimum requirements for text of size 16px and weight of 400",
"messageArgs": [
"2.32",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@
"dom": "/html[1]/body[1]/div[1]",
"aria": "/document[1]/button[1]"
},
"reasonId": "Fail_1",
"reasonId": "fail_contrast",
"message": "Text contrast of 3.86 with its background is less than the WCAG AA minimum requirements for text of size 16px and weight of 400",
"messageArgs": [
"3.86",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@
"dom": "/html[1]/body[1]/p[1]",
"aria": "/document[1]/paragraph[1]"
},
"reasonId": "Potential_graphic_background",
"reasonId": "potential_graphic_background",
"message": "Verify the contrast ratio of the text against the lightest and the darkest colors of the background meets the WCAG AA minimum requirements for text of size 16px and weight of 400",
"messageArgs": [
"1.00",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@
"dom": "/html[1]/body[1]/p[1]",
"aria": "/document[1]/paragraph[1]"
},
"reasonId": "Potential_graphic_background",
"reasonId": "potential_graphic_background",
"message": "Verify the contrast ratio of the text against the lightest and the darkest colors of the background meets the WCAG AA minimum requirements for text of size 16px and weight of 400",
"messageArgs": [
"2.82",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@
"dom": "/html[1]/body[1]/p[1]",
"aria": "/document[1]/paragraph[1]"
},
"reasonId": "Fail_1",
"reasonId": "fail_contrast",
"message": "Text contrast of 2.11 with its background is less than the WCAG AA minimum requirements for text of size 16px and weight of 400",
"messageArgs": [
"2.11",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@
"dom": "/html[1]/body[1]/div[1]/p[1]",
"aria": "/document[1]/paragraph[1]"
},
"reasonId": "Fail_1",
"reasonId": "fail_contrast",
"message": "Text contrast of 2.11 with its background is less than the WCAG AA minimum requirements for text of size 16px and weight of 400",
"messageArgs": [
"2.11",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@
"dom": "/html[1]/body[1]/p[1]",
"aria": "/document[1]/paragraph[1]"
},
"reasonId": "Fail_1",
"reasonId": "fail_contrast",
"message": "Text contrast of 2.32 with its background is less than the WCAG AA minimum requirements for text of size 16px and weight of 400",
"messageArgs": [
"2.32",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@
"dom": "/html[1]/body[1]/span[1]",
"aria": "/document[1]"
},
"reasonId": "Potential_graphic_background",
"reasonId": "potential_graphic_background",
"message": "Verify the contrast ratio of the text against the lightest and the darkest colors of the background meets the WCAG AA minimum requirements for text of size 16px and weight of 400",
"messageArgs": [
"1.00",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,8 +28,8 @@
"dom": "/html[1]/body[1]/p[1]",
"aria": "/document[1]/paragraph[1]"
},
"reasonId": "Pass_0",
"message": "Rule Passed",
"reasonId": "pass",
"message": "The contrast ratio of text with its background meets WCAG AA requirements",
"messageArgs": [
"12.63",
16,
Expand All @@ -52,7 +52,7 @@
"dom": "/html[1]/body[1]/p[2]",
"aria": "/document[1]/paragraph[2]"
},
"reasonId": "Fail_1",
"reasonId": "fail_contrast",
"message": "Text contrast of 3.86 with its background is less than the WCAG AA minimum requirements for text of size 16px and weight of 400",
"messageArgs": [
"3.86",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@
"dom": "/html[1]/body[1]/button[1]",
"aria": "/document[1]/button[1]"
},
"reasonId": "Fail_1",
"reasonId": "fail_contrast",
"message": "Text contrast of 3.86 with its background is less than the WCAG AA minimum requirements for text of size 13.3333px and weight of 400",
"messageArgs": [
"3.86",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@
"dom": "/html[1]/body[1]/p[1]",
"aria": "/document[1]/paragraph[1]"
},
"reasonId": "Potential_same_color",
"reasonId": "potential_same_color",
"message": "The foreground text and its background color are both detected as #ffffff. Verify the text meets the WCAG AA requirements for minimum contrast",
"messageArgs": [
"1.00",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,8 +26,8 @@
"dom": "/html[1]/body[1]/label[1]",
"aria": "/document[1]"
},
"reasonId": "Pass_0",
"message": "Rule Passed",
"reasonId": "pass",
"message": "The contrast ratio of text with its background meets WCAG AA requirements",
"messageArgs": [
"3.54",
16,
Expand Down
Loading

0 comments on commit be994c6

Please sign in to comment.