Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Consolidating issues for handling whitespace where the spec algorithm breaks down #16

Open
accdc opened this issue Apr 20, 2018 · 2 comments
Milestone

Comments

@accdc
Copy link
Contributor

accdc commented Apr 20, 2018

As requested in the last ARIA Caucus meeting, I've copied out the relevant text alternative algorithm below and edited the text accordingly. The spec text is the same, but embedded notes starting with "BG Note:" identify where content was inserted.

To summarize, when writing the AccName Computation Prototype, I ran across many of the same issues encountered by browser implementors, where specific steps as given by the algorithm cannot be followed exactly without introducing results that contradict common sense outcomes, or deviate from the expected results by end users. So to address this, I had to insert processes that deal with these scenarios without deviating from the steps of the algorithm.

So the goal, which is the same one that browser implementors are having to solve right now as well, is to provide the most accessible results that fit the highest percentage of scenarios and that meet the general expectations of the widest range of people possible in order to provide the most reliable results that are easily human readable by end users. This is the highest point that we can raise this bar, because we have to accept that it is literally impossible to account for every bleeding edge case or for non-standard implementations that intentionally diverge from general majority expectations.

The AccName Computation Prototype
https://github.com/whatsock/w3c-alternative-text-computation
already includes all of the additional features noted below.

I've attached a test page to this issue so you can download and run the AccName Prototype code locally by editing the test example as desired, which loads the latest executable code directly from GitHub to reproduce the examples as noted inline.
CreateYourOwn.zip

[Spec text]

  1. Compute the text alternative for the current node:

A. If the current node is hidden and is not directly referenced by aria-labelledby or aria-describedby, nor directly referenced by a native host language text alternative element (e.g. label in HTML) or attribute, return the empty string.

B. Otherwise:

• if computing a name, and the current node has an aria-labelledby attribute that contains at least one valid IDREF, and the current node is not already part of an aria-labelledby traversal, process its IDREFs in the order they occur:

• or, if computing a description, and the current node has an aria-describedby attribute that contains at least one valid IDREF, and the current node is not already part of an aria-describedby traversal, process its IDREFs in the order they occur:

BG Note: After computing the completed name for each aria-labelledby or aria-describedby reference using the algorithm steps below, a space is added at the beginning and end of the returned name to prevent unwanted concatenation with other ID refs or returned names from other nodes if applicable. E.G JS: (Name = " " + Name + " ";) This fulfills the expectation that, in the vast majority of cases, each referenced ID will be visually seperated and should not be mashed together without contextually differentiating each part.

i. Set the accumulated text to the empty string.
ii. For each IDREF:
a. Set the current node to the node referenced by the IDREF.
b. Compute the text alternative of the current node beginning with step 2. Set the result to that text alternative.
c. Append the result, with a space, to the accumulated text.
iii. Return the accumulated text.

C. Otherwise, if computing a name, and if the current node has an aria-label attribute whose value is not the empty string, nor, when trimmed of white space, is not the empty string:

• If traversal of the current node is due to recursion and the current node is an embedded control as defined in step 2E, ignore aria-label and skip to rule 2E.

• Otherwise, return the value of aria-label.

BG Note: After returning the value of aria-label, a space is added at the beginning and end of the returned name to prevent unwanted concatenation with other elements like so (Name = " " + Name + " ";), but this is only done if the current node is the same as root node. If the current node is an element being parsed recursively as a child of root node however, then no additional spacing is added. This is meant to handle situations like the following when processing the name for H1:

<h1>(<span aria-label="B">Q</span><span aria-label="E">E</span><span aria-label="G">D</span>)</h1>

Where the name of heading should be "(BEG)", and not "( B E G )".

D. Otherwise, if the current node's native markup provides an attribute (e.g. title) or element (e.g. HTML label) that defines a text alternative, return that alternative in the form of a flat string as defined by the host language, unless the element is marked as presentational (role="presentation" or role="none").

BG Note: After returning the value of label on form fields, or alt on images, or title, a space is added at the beginning and end of the returned name to prevent unwanted concatenation with other elements, like so (Name = " " + Name + " ";). This is needed to prevent alt and title attributes on images from being mashed together with adjacent content, which is the most desirable result in the vast majority of cases for end users.

E. Otherwise, if the current node is a control embedded within the label (e.g. the label element in HTML or any element directly referenced by aria-labelledby) for another widget, where the user can adjust the embedded control's value, then include the embedded control as part of the text alternative in the following manner:

BG Note: After returning the widget value using the algorithm below, a space is added at the beginning and end of the returned name to prevent unwanted concatenation with other elements, like so (Name = " " + Name + " ";). This is needed to prevent the values of visually separated controls from being mashed together with adjacent controls or content, which is the most desirable result in the vast majority of cases for end users.

• If the embedded control has role textbox, return its value.

• If the embedded control has role menu button, return the text alternative of the button.

• If the embedded control has role combobox, return the text alternative of the chosen option.

BG Note: As we discussed earlier, listbox needs to be added here to support embedded value parsing of selected options to cover scenarios when listbox is standalone or embedded within a combobox. However, we also need to add grid and tree here as well to account for the same thing, because these too are now supported as child widgets in ARIA 1.1. Otherwise, value will be returned for listbox but not for tree or grid as expected, even though all of these use aria-selected as the selection mechanism. Support for all these combinations has already been added in the AccName Prototype to account for the supported widgets of role=combobox.

• If the embedded control has role range (e.g., a spinbutton or slider):
• If the aria-valuetext property is present, return its value,
• Otherwise, if the aria-valuenow property is present, return its value,
• Otherwise, use the value as specified by a host language attribute.

F. Otherwise, if the current node's role allows name from content, or if the current node is referenced by aria-labelledby, aria-describedby, or is a native host language text alternative element (e.g. label in HTML), or is a descendant of a native host language text alternative element:

BG Note: After returning name from content for the current node, a space is added at the beginning and end of the returned name to prevent unwanted concatenation with other elements, like so (Name = " " + Name + " ";), but this only occurs when current node is determined to be a block level type element. Otherwise, no spacing is added. This is needed to prevent the content of visually separated controls from being mashed together with adjacent elements, while also making sure that inline text nodes and inline elements are not undesirably seperated. This is important to ensure that the following examples return the correct results:

<b>T<i>e</i>st</b> = "Test"
<div>T<br>e<div>st</div></div> = "T e st"

i. Set the accumulated text to the empty string.

ii. Check for CSS generated textual content associated with the current node and include it in the accumulated text. The CSS :before and :after pseudo elements can provide textual content for elements that have a content model.
• For :before pseudo elements, User agents MUST prepend CSS textual content, without a space, to the textual content of the current node.
• For :after pseudo elements, User agents MUST append CSS textual content, without a space, to the textual content of the current node.

BG Note: This spec text contradicts the intended purpose of pseudo elements and what people can use them for, and introduces accessibility issues if the naming computation doesn't account for them. As such, to account for block level versus inline styling properties that are acceptable within pseudo elements, the following is done instead. After returning the pseudo element content, a space is added at the beginning of :after and at the end of :before to prevent unwanted concatenation with other visually seperated content, but this only occurs when the pseudo element includes block level properties. Otherwise, no spacing is added. This is needed to account for fluid layouts where visually seperated content can be reliably conveyed within the accessibility tree, while also preserving default feedback for standard inline representations.

iii. For each child node of the current node:
a. Set the current node to the child node.
b. Compute the text alternative of the current node beginning with step 2. Set the result to that text alternative.
c. Append the result to the accumulated text.

iv. Return the accumulated text.
Important: Each node in the subtree is consulted only once. If text has been collected from a descendant, but is referenced by another IDREF in some descendant node, then that second, or subsequent, reference is not followed. This is done to avoid infinite loops.

G. Otherwise, if the current node is a Text node, return its textual contents.

H. Otherwise, if the current node is a descendant of an element whose Accessible Name or Accessible Description is being computed, and contains descendants, proceed to 2F.i.

I. Otherwise, if the current node has a Tooltip attribute, return its value.

BG Note: After returning the tooltip, a space is added at the beginning and end of the returned name to prevent unwanted concatenation with other elements, like so (Name = " " + Name + " ";). This is needed to prevent visually separate content from being mashed together with adjacent content, which is the most desirable result in the vast majority of cases for end users.

@minorninth
Copy link

Based on discussions at the ARIA F2F, we're suggesting:

  • Whether whitespace is added to a node should be based on whether the node is inline or block.
  • However, form controls should always get whitespace
  • Also, the title attribute should always get whitespace

@accdc
Copy link
Contributor Author

accdc commented May 3, 2018

Thanks, I believe I've made all of the corrections we spoke of, now pushed live to
https://github.com/whatsock/w3c-alternative-text-computation

Title attributes still retain spacing.

Also, as we spoke of yesterday, aria-labelledby and aria-describedby references still add whitespace around them to differentiate them from visually separate areas, and also to handle issues when pulling content from DOM nodes when beginning and ending whitespace is automatically trimmed which would lead to problems in the naming computation if no whitespace were added automatically as well.

All interactive ARIA widget controls, including native form fields and buttons, also include whitespace; with one exception for role="link" which does not add whitespace to handle similar behavior seen with native links.

CSS pseudo elements do not add any whitespace by default, unless block level styling properties are detected. All block level elements and relevant block styling will add spacing, so too will line breaks. All inline styling and inline elements and standard text nodes do not add any spacing. All other cases such as with aria-label do not add spacing either.

There are specific test cases within the folder named "Proposed Name and Description Tests" within the above repo that exercise all of the scenarios we spoke of, and these are the ones I specifically test for and work to pass before moving into any of the others.

Please let me know if I've missed any of the things we went over.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants