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

NVDA skips elements with zero width or height #13897

Closed
patrickhlauke opened this issue Jul 13, 2022 · 22 comments
Closed

NVDA skips elements with zero width or height #13897

patrickhlauke opened this issue Jul 13, 2022 · 22 comments

Comments

@patrickhlauke
Copy link

patrickhlauke commented Jul 13, 2022

Steps to reproduce:

Actual behavior:

The zero-value progress bar is completely omitted from NVDA's output, despite being exposed correctly by the browser's accessibility tree. Presumably, this is an NVDA-specific heuristic?

Video recording of the current behaviour - note how the first progress bar is completely skipped

bootstrap-progress-bar-nvda.mp4

Happens in Chrome and Firefox.

JAWS correctly announces the zero-value (and visually zero-width) progress bar.

Screenshot from Chrome's Developer Tools, showing that the ARIA-fied progress bar is correctly exposed in the accessibility tree

Expected behavior:

I'd expect the CSS width not to influence whether or not the content is announced - not going by heuristics, but just by what is exposed explicitly in the accessibility tree.

System configuration

NVDA installed/portable/running from source:

NVDA installed

NVDA version:

2022.1

Windows version:

Windows 10.0.19044 Build 19044

Name and version of other software in use when reproducing the issue:

Chrome 103.0.5060.114
Firefox 102.0.1 (64-bit)

Other information about your system:

N/A

Other questions

Does the issue still occur after restarting your computer?

Yes

Have you tried any other versions of NVDA? If so, please report their behaviors.

No

If NVDA add-ons are disabled, is your problem still occurring?

Yes

Does the issue still occur after you run the COM Registration Fixing Tool in NVDA's tools menu?

Yes

@patrickhlauke
Copy link
Author

Note that currently, those example progress bars based on ARIA lack an accessible name. However, even after adding an accName (see twbs/bootstrap#36732) NVDA still omits the zero-width element from its output.

@feerrenrut
Copy link
Contributor

In short, this is intentional.
See the aria-hidden spec: https://w3c.github.io/aria/#aria-hidden

Exposing non-visible elements to screen reader users would result in a noisy and difficult user experience.
Historically, it has been common to visually hide elements that aren't there for user consumption.

There is more discussion on #12501

You can use aria-label to provide an alternative name/text for an element.
If it really is desirable to make some elements only available to screen reader users take a look at:
https://webaim.org/techniques/css/invisiblecontent/

@patrickhlauke
Copy link
Author

@feerrenrut however, this is NVDA's heuristic, correct? both chrome and firefox expose elements appropriately through the accessibility API/tree when they have a zero width or height, so they do consider them "rendered" - compared to when they have display:none, which fully omits them from the browser's accessibility tree. which is why JAWS will announce the element.

i'd say NVDA should rely on what it receives from the browser (which is supposed to handle this aspect of whether or not it considers an element "rendered, and thus exposed to AT", rather than applying its own additional heuristics (which then differ from those of other screen readers).

@seanbudd
Copy link
Member

Please read the linked specs, specifically:

User agents determine an element's hidden status based on whether it is rendered, and the rendering is usually controlled by CSS.

from the aria-hidden spec: https://w3c.github.io/aria/#aria-hidden

@patrickhlauke
Copy link
Author

"User agent" in this case being the browser, which in this case has determined that the element is indeed considered "rendered", since it's exposing it via the accessibility API. NVDA then runs extra heuristics on top of what the browser deems rendered.

@seanbudd
Copy link
Member

Yes, this is an intentional behaviour for the reasons discussed earlier.

Exposing non-visible elements to screen reader users would result in a noisy and difficult user experience.
Historically, it has been common to visually hide elements that aren't there for user consumption.

aria-hidden has historically been determined differently across browsers. It is up to the screen reader to provide a consistent user experience.

@patrickhlauke
Copy link
Author

patrickhlauke commented Jul 14, 2022

fine, if you can't see the problem of "browsers are inconsistent, so screen readers will apply their own inconsistent heuristics to patch that" and how that doesn't actually make things more consistent...

so we now have this situation where chrome+jaws, firefox+jaws, chrome+talkback on android, chrome+voiceover on macOS, firefox_voiceover on macos (though it's broken in other ways), safari+voiceover on macos do announce that zero width progress bar element, and chrome+nvda, firefox+nvda, safari+voiceover on iOs don't...

@feerrenrut
Copy link
Contributor

@patrickhlauke in this discussion care should be taken when using the term "rendered", the meaning of this can easily be open to interpretation, there are different render targets. One target may be MSAA/IA2 (a simple version of this tree is shown in the dev tools), another render target is the visual picture displayed by the browser.

If something is not visible, it is not important to sighted users. If it is not important to sighted users, then why should it be important to screen reader users.

The example given is a progress bar with zero width. It couples the visual presentation with the semantic information. The progress bar should have separate elements for the visual presentation

@feerrenrut
Copy link
Contributor

The problematic sample from Bootstrap is:

<div class="progress">
  <div class="progress-bar" role="progressbar" aria-valuenow="0" aria-valuemin="0" aria-valuemax="100"></div>
</div>

Moving the semantics onto the always visible element resolves the issue:

<div class="progress"  role="progressbar" aria-valuenow="0" aria-valuemin="0" aria-valuemax="100">
  <div class="progress-bar"></div>
</div>

@patrickhlauke
Copy link
Author

patrickhlauke commented Jul 14, 2022

One target may be MSAA/IA2 (a simple version of this tree is shown in the dev tools), another render target is the visual picture displayed by the browser.

sure, but that's my point: these are currently exposed via the accessibility tree, so the browsers do deem these elements as something that should be conveyed, and then additional heuristics are applied by NVDA (and VO on iOS, but that's notorious for doing that sort of "we know best" approach).

i'm well aware of how to work around the issue, so not asking for advice on how to correct bootstrap's markup (which we'll grudgingly do, see twbs/bootstrap#36736), but rather interested in the fundamental principle of running extra heuristics over what the browser already determined and exposed/didn't expose via the accessibility tree...

anyway, i'll leave it at that here, clearly not going to move the needle here on why the heuristics should be left up to browsers rather than ATs...

but i will note that this - the fact that different secret-sauce heuristics are applied by AT - is exactly why many developers struggle/make faux-pas when it comes to more complex aspects of accessibility. it goes back to the old days of "you can't guarantee how it will be (aurally, in this case) rendered, so you just have to test in every combination" web development.

@feerrenrut
Copy link
Contributor

I'm not sure that I agree that a zero width or height is merely a heuristic for visibility, it seems logically direct to me.

When considering whether this should be a browser or AT decision there's also the hugely variable nature of disabilities to consider. It can't be a one size fits all, to cater to this the decisions about final presentation does need to be left to the AT/users. The current reality is that a browser does not dictate how AT to should present information or even which information is important, it only attempts to make the information available.

I can sympathize with difficulty of testing many combinations, NVDA has to work not only with web tech (unfortunately the browser layer does not abstract many of the details required), but also several other APIs for applications and the OS itself.

Thanks for raising an issue and participating in the discussion.

@feerrenrut
Copy link
Contributor

I'm not sure that I agree that a zero width or height is merely a heuristic for visibility, it seems logically direct to me.

To prevent confusion for anyone reading this issue, I'm referring to the width and height of the object as it is exposed by the browser via the accessibility API (in this case IA2), rather than the CSS width and height, NVDA does not parse CSS or HTML.

@BlindGuyNW
Copy link

BlindGuyNW commented Nov 21, 2023

I tend to agree with @patrickhlauke here. NVDA should render the contents of the accessibility tree as presented. I just encountered this with a few interactive components (radio buttons and checkboxes), which are hidden visually but ought to still be visible with the screen reader. I feel like NVDA is overstepping because the author didn't explicitly hide the controls with aria-hidden, all they did was set CSS width to 0. The controls are still in the DOM and accessibility trees, but can't be interacted with by an NVDA user. A mouse user can click on the labels for the components, which are visible and work as expected.

@Adriani90
Copy link
Collaborator

but that's notorious for doing that sort of "we know best" approach).

anyway, i'll leave it at that here, clearly not going to move the needle here on why the heuristics should be left up to browsers rather than ATs...

@patrickhlauke I totally understand your point here. However, browsers still expose things via the accessibility API in a very inconsistent way. In your case it might happen that it is exposed consistently and that ATs applied their heuristics because there was a time when this was not the case. But still, we don't have any committments from browser vendors that they all will apply the rendering standards as to comply with the best accessibility requirements.
In my view we still need a lot of independent heuristics in order to make as many different browsers accessible as possible but also not breaking user experience or making browsing through the interent very inefficient.
Can you please elaborate more on the advantages of an user having such elements being red out by the screen reader? We need some clear practical use cases.

@BlindGuyNW wrote:

I just encountered this with a few interactive components (radio buttons and checkboxes), which are hidden visually but ought to still be visible with the screen reader. I feel like NVDA is overstepping because the author didn't explicitly hide the controls with aria-hidden, all they did was set CSS width to 0. The controls are still in the DOM and accessibility trees, but can't be interacted with by an NVDA user. A mouse user can click on the labels for the components, which are visible and work as expected.

If the control and the label are associated and only the control is hidden, then NVDA should see the label though. In browse mode when pressing enter, NVDA calls a mouse click event as far as I know. So pressing enter on the visible label should still work for an NVDA user as well. Can you please provide an example?

@BlindGuyNW
Copy link

@Adriani90 Please see this codepen. Niehter the radio buttons nor the label are exposed to nVDA. If you Tab into the frame and navigate with browse mode off it behaves a bit better but surely we want to expose things in browse mode to avoid confusion?

@ramoncorominas
Copy link

@BlindGuyNW I cannot reproduce the issue, if I go to that Codepen I can tab to the options and they are read as "radio button" checked or unchecked, and I can use arrow keys to change the selected option as always. I'm using NVDA 2023.3, both with Firefox or Chrome the behavior is the same

@Adriani90
Copy link
Collaborator

I am not able to reproduce the issue @BlindGuyNW provided in the codepen, I can access the radio buttons and their label both in focus and in browse mode. The only thing that NVDA does not report is the state change when you press space bar. But this is another issue.

@BlindGuyNW
Copy link

I'm using Google Chrome, to be clear. The radio buttons behave reasonably with tab but do not appear in browse mode at all.

They do appear and work fine with Jaws however.

@BlindGuyNW
Copy link

I would like to understand why our experiences, or perhaps expectations, are so different. When I navigate to the codepen preview frame, I hear "grouping select a maintenance drone." I would expect to then be able to down-arrow in browse mode to read the radio buttons for selection. Instead, when I hit downarrow I am simply taken to the end of the grouping with no radio buttons or labels of any kind.

@Adriani90
Copy link
Collaborator

Ok sorry it seems I can reproduce in Chrome as well.
According to this docs, it seems opacity:0 is explicitely not treated as invisible, so NVDA should definitely render this in browse mode as well.
https://chromium.googlesource.com/chromium/src/+/HEAD/docs/accessibility/browser/offscreen.md

@jcsteh why is this working in Firefox but not in Chrome? Any idea? Focus mode works in both browsers as expected.

Regarding the progress bar without any CSS width or heighth atributes, I am still not convinced this should be exposed to NVDA. I guess there are a lot of people using such elements without width or heighth. Adding opacity:0 should make it visible I guess but still not consistent in every browser.

@BlindGuyNW
Copy link

I note that removing opacity: 0 has no impact on what is rendered with NVDA. The radio buttons still are not shown in browse mode. Removing width: 0; and keeping opacity: 0; on the other hand, puts them in as expected.

@ramoncorominas
Copy link

@BlindGuyNW You are right, I did not test it properly on Google Chrome. It works as expected in focus mode but not in browse mode.

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

6 participants