diff --git a/__tests__/spelling-ignore.yml b/__tests__/spelling-ignore.yml index 0ff0d79ef5..e7d0c16864 100644 --- a/__tests__/spelling-ignore.yml +++ b/__tests__/spelling-ignore.yml @@ -138,7 +138,7 @@ - ozplayer - GitHub -# Test case anamolies +# Test case anomalies - brewitt-taylor - level2-frame1 - level1-frame2 @@ -148,6 +148,9 @@ - Sumei - Tuttle - lnik # intentional misspelling +- ngizmo +- nspecification +- thelabel # Attributes (repeated words with casing as retext-spell has no config to ignore casing) - href @@ -179,6 +182,9 @@ - x1 - y1 +# HTML character references +- nbsp + # DOM Events - auxclick - compostionend @@ -245,6 +251,12 @@ - disambiguated - superclass - grey +- substring +- initialisms +- sublist +- tokenize +- tokenized +- subsequence # Parts of Unicode - 000A @@ -254,6 +266,8 @@ - 4E00 - 9FFF - 4E00–9FFF +- 00A0 +- KD # JSON attributes/ metadata/ methods - examples diff --git a/_rules/visible-label-in-accessible-name-2ee8b8.md b/_rules/visible-label-in-accessible-name-2ee8b8.md index 65daa251c2..0997ad1f0a 100755 --- a/_rules/visible-label-in-accessible-name-2ee8b8.md +++ b/_rules/visible-label-in-accessible-name-2ee8b8.md @@ -24,6 +24,7 @@ acknowledgments: authors: - Anne Thyme Nørregaard - Bryn Anderson + - Dan Tripp - Jey Nandakumar funding: - WAI-Tools @@ -35,11 +36,13 @@ This rule applies to any element for which all the following is true: - The element has a [semantic role][] that is a [widget][widget role] that [supports name from content][]; and - The element has [visible text content][]; and -- The element has an `aria-label` or `aria-labelledby` attribute. +- The element has an `aria-label` or `aria-labelledby` attribute; and +- Neither the element's accessible name nor its visible label contains any abbreviations; and +- Every word that appears in both the element's accessible name and its visible label uses the same spelling and hyphenation in both places. ## Expectation -For each target element, all [text nodes][] in the [visible text content][] [match characters][] and are contained within the [accessible name][] of this target element, except for characters in the [text nodes][] used to express [non-text content][]. Leading and trailing [whitespace][] and difference in case sensitivity should be ignored. +For each target element, the [visible inner text][] is contained within the [accessible name][] according to the [label in name algorithm][]. ## Background @@ -47,9 +50,17 @@ This rule applies to elements with a [widget role][] that [support name from con The understanding document of [2.5.3 Label in Name][understand253] use the term "symbolic text characters" to refer to a type of [non-text content][] that uses text characters as symbols, such as using "x" to mean "close". This rule considers them as "characters expressing non-text content". Unicode emojis are another example of characters expressing non-text content, although these are not "symbolic text characters". +If the target element contains an [image of text](https://www.w3.org/TR/WCAG22/#label-in-name), it may pass this rule but fail [2.5.3 Label in Name][understand253] (because the accessible name should then match the text inside the image, which is not taken into account by this rule). So further testing is needed. This case might be handled by a different rule in the future. + ### Assumptions -This rule assumes that all resources needed for rendering the page are properly loaded. Checking if resources are missing is out of the scope of rules. Missing resources may be rendered as text (for example, missing `img` are rendered as their `alt` attribute). +This rule assumes that the [visible inner text][] is equal to the [label as defined by WCAG](https://www.w3.org/wai/wcag22/understanding/label-in-name#dfn-label), even though "label" is not precisely defined at this point in history. + +This rule assumes that the visible label isn't rearranged with CSS so that it appears to the user in a different order than it appears in the DOM. + +This rule assumes that the visible label doesn't use CSS to add whitespace where none exists in the DOM. + +This rule - specifically, the [label in name algorithm][] that this rule relies on - assumes that content within parentheses can be ignored. ("Parentheses" are also known as "round brackets".) This is important because the algorithm's treatment of parentheses is to remove them and all characters within them. This assumption is almost always true in English. Exceptions include links with names such "Dune (1984 film)" and "Dune (2021 film)". This assumption is known to be often false in languages other than English, such as German (where parentheses indicate dual states) and Arabic (where parentheses are often used as quotation marks). Violations of this assumption will, in real-world scenarios, more often result in a false negative for this rule rather than a false positive. ### Accessibility Support @@ -66,7 +77,7 @@ Implementation of [Presentational Roles Conflict Resolution][] varies from one b #### Passed Example 1 -This link has [visible][] text that matches the [accessible name][]. +This link has [visible inner text][] that is equal to the [accessible name][]. ```html ACT rules @@ -74,23 +85,23 @@ This link has [visible][] text that matches the [accessible name][]. #### Passed Example 2 -This link has [visible][] text that, ignoring trailing whitespace, matches the [accessible name][]. +This link has [visible inner text][] that, ignoring whitespace, is equal to the [accessible name][]. ```html -ACT rules +ACT rules ``` #### Passed Example 3 -This link has [visible][] text that, ignoring case, matches the [accessible name][]. +This link has [visible inner text][] that, ignoring case, is equal to the [accessible name][]. ```html -ACT rules +ACT rules ``` #### Passed Example 4 -This button has [visible][] text that is contained within the [accessible name][]. +This button has [visible inner text][] that is contained within the [accessible name][] according to the [label in name algorithm][]. ```html @@ -98,7 +109,7 @@ This button has [visible][] text that is contained within the [accessible name][ #### Passed Example 5 -This button has [visible][] text that does not need to be contained within the [accessible name][], because the "x" text node is [non-text content][]. Note: this would need to meet SC 1.1.1 Non text content. +This button has [visible inner text][] that does not need to be contained within the [accessible name][], because the "x" text node is [non-text content][]. Note: this would need to meet SC 1.1.1 Non text content. ```html @@ -106,7 +117,7 @@ This button has [visible][] text that does not need to be contained within the [ #### Passed Example 6 -This `button` element has the text "search" rendered as an magnifying glass icon by the font. Because the text is rendered as [non-text content][], the text does not need to be contained within the [accessible name][]. +This `button` element has the text "search" rendered as a magnifying glass icon by the font. Because the text is rendered as [non-text content][], the text does not need to be contained within the [accessible name][]. ```html @@ -118,11 +129,119 @@ This `button` element has the text "search" rendered as an magnifying glass icon ``` +#### Passed Example 7 + +This button has [visible inner text][] that, according to the [label in name algorithm][], is contained within the [accessible name][]. This example shows why the [label in name algorithm][] uses the [visible inner text][] and not the [visible text content][]: the `

` tags insert whitespace into the result in the former but not the latter. + +```html + +``` + +#### Passed Example 8 + +(Similar to previous example.) This link has [visible inner text][] that, according to the [label in name algorithm][], is contained within the [accessible name][]. This example shows why the [label in name algorithm][] uses the [visible inner text][] and not the [visible text content][]: the `

` tags insert whitespace into the result in the former but not the latter. + +```html + +
Some article
+

by John Doe

+
+``` + +#### Passed Example 9 + +The [visible inner text][] of this link is "ACT" (with no spaces) because of the explicit styles of `display: inline` on the `p` elements and the absence of whitespace between the `div` elements. The cases of `display: inline` and `display: block` are handled by the definition of [visible inner text of an element][]. This example shows that the definition agrees with the visual rendering done by the browser. + +```html + +
A
+
C
+
T
+
+``` + +#### Passed Example 10 + +The [visible inner text][] is "Download specification". The words "the" and "gizmo" aren't part of it. + +```html +Download the gizmo specification +``` + +#### Passed Example 11 + +The [visible inner text][] is "Download specification", which includes a space character between the two words due to the [second clause of the definition of visible inner text of a text node][]. + +```html +Download specification +``` + +#### Passed Example 12 + +This example shows that the [visible inner text][] isn't always the same as the [`innerText` IDL attribute](https://html.spec.whatwg.org/multipage/dom.html#the-innertext-idl-attribute). The visible inner text is "Download specification". The `innerText` is `Download \ngizmo\nspecification`. This rule uses the visible inner text - not innerText. + +```html + +Download gizmo specification +``` + +#### Passed Example 13 + +This example shows that the [label in name algorithm][] handles many kinds of whitespace. + +```html + + compose   
+ email +
+``` + +#### Passed Example 14 + +This example passes the rule because "YYYY-MM-DD" is in round brackets. Text in round brackets is removed by the [label in name algorithm][], because it is not normally spoken by speech-input users. + +```html + +``` + +#### Passed Example 15 + +This passes for two reasons: 1) because the ellipsis ("…") is [non-text content][], and 2) because the ellipsis is neither a letter nor a digit and so is filtered out by the [label in name algorithm][]. + +```html + +``` + +#### Passed Example 16 + +This passes because the [label in name algorithm][] effectively ignores all punctuation and emoji, in both the visible inner text and the accessible name, as long as they don't break up words. + +```html + +``` + ### Failed #### Failed Example 1 -This link has [visible][] text that is different from the [accessible name][]. +This link has [visible inner text][] that is very different from the [accessible name][]. ```html ACT rules @@ -130,7 +249,7 @@ This link has [visible][] text that is different from the [accessible name][]. #### Failed Example 2 -This button has [visible][] text that is only partially contained within the [accessible name][]. +This button has [visible inner text][] that is only partially contained within the [accessible name][]. ```html @@ -138,33 +257,121 @@ This button has [visible][] text that is only partially contained within the [ac #### Failed Example 3 -This link has [visible][] text with mathematical symbols, that does not match the [accessible name][] because the mathematical symbols were written out in the accessible name. This is [explicitly mentioned in WCAG](https://www.w3.org/WAI/WCAG22/Understanding/label-in-name#mathematical-expressions-and-formulae). +This button has [visible inner text][] that is fully contained within the [accessible name][] when viewed as a character-by-character substring. But that does not satisfy the [label in name algorithm][], which works on full words. So this fails the rule. ```html -Proof of 2×2=4 +Discover It ``` #### Failed Example 4 -This link has [visible][] text does not match the [accessible name][] because there is a hyphen in the accessible name. +This link's [accessible name][] contains two tokens (according to the[label in name algorithm][]) and the [visible inner text][] contains one token. So it fails the rule. ```html -nonstandard +justice ``` #### Failed Example 5 -This link has [visible][] text does not match the [accessible name][] because there are extra spaces in the accessible name. +The rule has no special handling for acronyms or initialisms. + +```html +W C A G +``` + +#### Failed Example 6 + +This link has [visible inner text][] with mathematical symbols and is not contained within the [accessible name][] because the mathematical symbols are represented as English words (not digits) in the accessible name. This is [explicitly mentioned in WCAG](https://www.w3.org/WAI/WCAG22/Understanding/label-in-name#mathematical-expressions-and-formulae). + +```html +Proof of 2×2=4 +``` + +#### Failed Example 7 + +This rule has no special handling for converting mathematical symbols into words, or vice versa. + +```html + +``` + +#### Failed Example 8 + +This button's accessible name contains the same tokens that are in the visible label. But they aren't in the same order, so it fails the sublist check part of the [label in name algorithm][], and so it fails the rule. + +```html + +``` + +#### Failed Example 9 + +This button's accessible name contains the word "the" in the middle of it, which causes the sublist check of the [label in name algorithm][] (in particular: the "consecutive" requirement of that check) to fail. So it fails the rule. + +```html + +``` + +#### Failed Example 10 + +This link's accessible name contains the same digits that are in the visible label, and in the same order. But they have different spaces and punctuation between them, so they are considered separate tokens. So this fails the rule. ```html 123.456.7890 ``` +#### Failed Example 11 + +This rule has no special handling which tries to guess when numbers have the same semantic meaning. It operates on tokens only. + +```html +2021 +``` + +#### Failed Example 12 + +This rule has no special handling which tries to guess when numbers have the same semantic meaning. It operates on tokens only. + +```html +fibonacci: 0112358132134 +``` + +#### Failed Example 13 + +This rule has no special handling for converting digits into words, or vice versa. + +```html +two thousand twenty-one +``` + +#### Failed Example 14 + +This rule has no special handling for converting digits into words, or vice versa. + +```html +2 0 2 3 +``` + +#### Failed Example 15 + +The [label in name algorithm][] works on full words. That is: it requires that each full word in the visible label ("1" in this case) is equal to a full word in the accessible name ("1a" in this case). Those two words - "1" and "1a" - are not equal, so this element fails the rule. + +```html +1 +``` + +#### Failed Example 16 + +The definition of [visible inner text][] doesn't treat text any differently if it's excluded from the accessibility tree with aria-hidden. So this rule effectively ignores aria-hidden. So this element fails the rule. + +```html +Download specification +``` + ### Inapplicable #### Inapplicable Example 1 -This `nav` is not a widget, so the [visible][] text does not need to match the [accessible name][]. +This `nav` is not a widget, so the [visible inner text][] does not need to match the [accessible name][]. ```html @@ -172,7 +379,7 @@ This `nav` is not a widget, so the [visible][] text does not need to match the [ #### Inapplicable Example 2 -This email text field does not need to have its [visible][] text match the [accessible name][]. The content of a textfield shows its value instead of its label; it does not [support name from content][supports name from content]. The label is usually adjacent to the textfield instead. +This email text field does not need to have its [visible inner text][] match the [accessible name][]. The content of a text field shows its value instead of its label; it does not [support name from content][supports name from content]. The label is usually adjacent to the text field instead. ```html
E-mail
@@ -181,7 +388,7 @@ This email text field does not need to have its [visible][] text match the [acce #### Inapplicable Example 3 -This `div` element does not have a widget role, so the [visible][] text does not need to match the [accessible name][]. +This `div` element does not have a widget role, so the [visible inner text][] does not need to match the [accessible name][]. ```html
Next
@@ -189,7 +396,7 @@ This `div` element does not have a widget role, so the [visible][] text does not #### Inapplicable Example 4 -This link has no [visible text content][]. +This link has no [visible inner text][]. ```html @@ -197,15 +404,31 @@ This link has no [visible text content][]. ``` +#### Inapplicable Example 5 + +This link's label contains an abbreviation, so it is not applicable. + +```html +University Ave. +``` + +#### Inapplicable Example 6 + +This word - non-standard / nonstandard - appears in both the element's accessible name and its visible label, using different hyphenation. So it's not applicable. + +```html +nonstandard +``` + [accessible name]: #accessible-name 'Definition of accessible name' -[match characters]: #matching-characters 'Definition of matching characters' +[label in name algorithm]: #label-in-name-algorithm 'Definition of Label in Name Algorithm' [non-text content]: https://www.w3.org/TR/WCAG22/#dfn-non-text-content 'WCAG Definition of Non-text content' [presentational roles conflict resolution]: https://www.w3.org/TR/wai-aria-1.2/#conflict_resolution_presentation_none 'Presentational Roles Conflict Resolution' [semantic role]: #semantic-role 'Definition of Semantic role' -[supports name from content]: https://www.w3.org/TR/wai-aria-1.2/#namefromcontent 'Definition of Supports name from contents' -[visible]: #visible 'Definition of visible' +[supports name from content]: https://www.w3.org/TR/wai-aria-1.2/#namefromcontent 'Definition of Supports name from content' +[understand253]: https://www.w3.org/WAI/WCAG22/Understanding/label-in-name.html +[visible inner text]: #visible-inner-text 'Definition of Visible inner text' +[visible inner text of an element]: #visible-inner-text:for-element 'Definition of Visible inner text of an element' +[second clause of the definition of visible inner text of a text node]: #visible-inner-text:for-text-clause-2 'Second clause of the definition of Visible inner text of a text node' [visible text content]: #visible-text-content 'Definition of Visible text content' -[whitespace]: #whitespace 'Definition of Whitespace' [widget role]: https://www.w3.org/TR/wai-aria-1.2/#widget_roles 'Definition of Widget role' -[text nodes]: https://dom.spec.whatwg.org/#text 'DOM text, 2020/08/18' -[understand253]: https://www.w3.org/WAI/WCAG22/Understanding/label-in-name.html diff --git a/package.json b/package.json index 5e37f27855..81eb3de640 100644 --- a/package.json +++ b/package.json @@ -48,6 +48,10 @@ "name": "Dagfinn Rømen", "url": "https://github.com/DagfinnRomen" }, + { + "name": "Dan Tripp", + "url": "https://github.com/dan-tripp-siteimprove" + }, { "name": "Daniël Strik", "url": "https://github.com/danistr" diff --git a/pages/glossary/label-in-name-algorithm.md b/pages/glossary/label-in-name-algorithm.md new file mode 100755 index 0000000000..fea9a74ef6 --- /dev/null +++ b/pages/glossary/label-in-name-algorithm.md @@ -0,0 +1,43 @@ +--- +title: Label in Name Algorithm +key: label-in-name-algorithm +unambiguous: true +objective: false +input_aspects: + - CSS styling + - DOM tree +--- + +To check whether an [element][] has its label contained in its name, follow this algorithm: + +Let `label` be the [visible inner text][] of the target element. Let `name` be the [accessible name][] of the target element. Both `label` and `name` are strings. + +Sub-algorithm to tokenize a string: + +1. Remove parentheses (U+0028 LEFT PARENTHESIS and U+0029 RIGHT PARENTHESIS, known colloquially as round brackets) and all characters that are between a left and right parenthesis. + - Don't do this for other kind of brackets such as square brackets and curly brackets. +1. Do Unicode [case folding][] on the string then convert it to [normalization form KD][]. +1. For each character that either a) represents non-text content, or b) isn't a letter or a digit: replace that character with a space character. + - For a) Judgment of "non-text" probably can't be fully automated. For example: "X" for "close" probably can be automated, but presumably there are more cases than this. + - For b) Use the [Unicode general categories "L" (Letter) and "N" (Number)][https://www.unicode.org/versions/Unicode17.0.0/core-spec/chapter-4/#G134153]. (This will exclude hyphens, punctuation, emoji, and more.) +1. Split the string into a list of strings, one string per word, according to the word segmentation rules for the [language of the element][https://html.spec.whatwg.org/multipage/dom.html#language]. + - This 'split' operation must: + - Effectively remove leading and trailing [whitespace][]. + - If the input string contains nothing but [whitespace][] before this operation: return an empty list. + - In English and most other European languages, a greedy [whitespace][] regular expression will accomplish this. In languages such as Thai, Chinese, and Japanese, it won't. + - A consequence of using the ACT definition of [whitespace][] here is that all kinds of whitespace are covered. That includes the Unicode code point U+00A0 NO-BREAK SPACE (NBSP), which can be represented by the HTML named character reference ` `. + +Then do the check: is the tokenized `label` a contiguous subsequence of the tokenized `name`? +- This 'contiguous subsequence' check has these properties: + - Each string comparison (between a list element in the tokenized label and a list element in the tokenized name) is a simple string equality check. + - The "contiguous" aspect means that it's crucial that the elements are consecutive in the original list. Put another way: a contiguous subsequence of X can be obtained by removing any number of tokens from the start and/or end (but not the middle) of X. For example: ["A", "B", "C"] is a contiguous subsequence of ["A", "B", "C", "D"]. ["A", "B", "D"] is not. + - An empty list is a contiguous subsequence of any list. + +If the answer is "yes" (that is: the tokenized 'label' is a contiguous subsequence of the tokenized 'name'), then this algorithm returns "is contained". Otherwise, it returns "is not contained". + +[accessible name]: #accessible-name 'Definition of accessible name' +[case folding]: https://www.w3.org/TR/charmod-norm/#dfn-case-folding +[element]: https://dom.spec.whatwg.org/#element +[normalization form KD]: https://www.unicode.org/glossary/#normalization_form_kd +[visible inner text]: #visible-inner-text 'Definition of Visible inner text' +[whitespace]: #whitespace 'Definition of whitespace' diff --git a/pages/glossary/visible-inner-text.md b/pages/glossary/visible-inner-text.md new file mode 100755 index 0000000000..419627baab --- /dev/null +++ b/pages/glossary/visible-inner-text.md @@ -0,0 +1,47 @@ +--- +title: Visible Inner Text +key: visible-inner-text +unambiguous: true +objective: true +input_aspects: + - CSS styling + - DOM tree +--- + +(The "visible inner text" defined here is similar to, but not the same as, [visible text content][] and [innerText](https://html.spec.whatwg.org/multipage/dom.html#the-innertext-idl-attribute).) + +The visible inner text of a node depends on the kind of node. + +The visible inner text of a [text node][] is: +1. if the [text node][] is [visible][], its visible inner text is its [data][] with whitespace normalized by replacing contiguous [whitespace][] with `" "` (U+0020 SPACE); +1. if the [text node][] is not [visible][], is [rendered][], and contains only [whitespace][], its visible inner text is `" "` (U+0020 SPACE); +1. otherwise, the visible inner text of the [text node][] is `""` (the empty string). + + +The visible inner text of an [element][] is: +1. if the [element][] is not [rendered][], its visible inner text is `""` (the empty string); +1. if the [element][] is [rendered][] and not [visible][] and has a [bounding box][] which has width greater than 0, its visible inner text is `" "` (U+0020 SPACE); +1. if the [element][] is [rendered][] and not [visible][] and has a [bounding box][] which has width of 0, its visible inner text is `""` (the empty string); +1. if the [element][] is a [`
`][
] element, its visible inner text is `"\n"` (U+000A END OF LINE). +1. if the [computed][] [`display`][display] property of the [element][] has an [outer display type][] of `block`, or an [inner display type][] of `table-caption`, the visible inner text of the [element][] is the concatenation of is `"\n"` (U+000A END OF LINE) plus the visible inner text of its children (in [tree order][] in the [flat tree][]) plus another `"\n"` (U+000A END OF LINE); +1. if the [computed][] [`display`][display] property of the [element][] has an [inner display type][] of `table-cell` or `table-row`, the visible inner text of the [element][] is the concatenation of `" "` (U+0020 SPACE) plus the visible inner text of its children (in [tree order][] in the [flat tree][]) plus another `" "` (U+0020 SPACE); +1. otherwise, the visible inner text of the [element][] is the concatenation of the visible inner text of its children (in [tree order][] in the [flat tree][]). + + +The visible inner text of any other node is the concatenation of the visible inner text of its children (in [tree order][] in the [flat tree][]). + +[bounding box]: https://www.w3.org/TR/css-ui-3/#valdef-box-sizing-border-box +[
]: https://html.spec.whatwg.org/#the-br-element +[computed]: https://drafts.csswg.org/css-cascade/#computed +[data]: https://dom.spec.whatwg.org/#concept-cd-data +[display]: https://drafts.csswg.org/css2/#propdef-display +[element]: https://dom.spec.whatwg.org/#element +[flat tree]: https://drafts.csswg.org/css-scoping/#flat-tree +[inner display type]: https://drafts.csswg.org/css-display/#inner-display-type +[outer display type]: https://drafts.csswg.org/css-display/#outer-display-type +[rendered]: https://html.spec.whatwg.org/#being-rendered +[text node]: https://dom.spec.whatwg.org/#text +[tree order]: https://dom.spec.whatwg.org/#concept-tree-order +[visible]: #visible +[visible text content]: #visible-text-content +[whitespace]: #whitespace diff --git a/pages/glossary/visible-text-content.md b/pages/glossary/visible-text-content.md index f39f0e0a15..c422e31173 100755 --- a/pages/glossary/visible-text-content.md +++ b/pages/glossary/visible-text-content.md @@ -8,10 +8,12 @@ input_aspects: - DOM tree --- -The _visible text content_ of an [element][] is a set of all [visible][] [text nodes][] that are [descendants][] in the [flat tree][] of this element +The _visible text content_ of an [element][] is a set of all [visible][] [text nodes][] that are [descendants][] in the [flat tree][] of this element. (This is similar to, but not the same as, [visible inner text][].) + [descendants]: https://dom.spec.whatwg.org/#concept-tree-descendant 'DOM tree descendant, 2020/08/18' [element]: https://dom.spec.whatwg.org/#element 'DOM element, 2020/08/18' [flat tree]: https://drafts.csswg.org/css-scoping/#flat-tree 'CSS draft, flat tree, 2020/08/18' [visible]: #visible +[visible inner text]: #visible-inner-text [text nodes]: https://dom.spec.whatwg.org/#text 'DOM text, 2020/08/18'