简体   繁体   中英

NVDA screenreader not reading alert message with latest Chrome version

I have created below HTML demonstration page. In that page a message is added to a div when selecting the "No" radiobutton. The div has aria-tags on it. The div in question has ID "lblErr" / "lblErr2".

 <!DOCTYPE html> <html lang="en"> <head> <meta charset="utf-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Screenreader Errormessage Test with Radiobuttons</title> </head> <body> <label id="instructionLbl"> Please select below </label> <div> <div id="firstItemGroup"> <label id="headerTextLbl"> Select no to generate the error message </label> <fieldset aria-labelledby="headerTextLbl"> <div id="selectionGroup1"> <table id="radioBtnTable"> <tbody> <tr> <td> <label for="button:conf:1">Yes</label> <div class="ui-radiobutton ui-widget"> <div class="ui-helper-hidden-accessible"> <input tabindex="1" id="button:conf:1" name="button:conf" type="radio" value="false" onchange="var errorDiv = document.getElementById('lblErr');while(errorDiv.hasChildNodes()){errorDiv.removeChild(errorDiv.lastChild);}"> </input> </div> </div> </td> <td> <label for="button:conf:2">No</label> <div class="ui-radiobutton ui-widget"> <div class="ui-helper-hidden-accessible"> <input tabindex="2" id="button:conf:2" name="button:conf" type="radio" value="false" onchange="var errorDiv = document.getElementById('lblErr');errorDiv.style.display = 'block';var newDiv = document.createElement('div');var spanOne = document.createElement('span');spanOne.classList.add('ui-message-error-icon');var spanTwo = document.createElement('span');spanTwo.classList.add('ui-message-error-detail');var errMsg = document.createTextNode('Very long error message with special red font, details, paragraphs and recovery suggestion is displayed here');spanTwo.appendChild(errMsg);newDiv.appendChild(spanOne);newDiv.appendChild(spanTwo);errorDiv.appendChild(newDiv);"> </input> </div> </div> </td> </tr> </tbody> </table> <div id="lblErr" style="display: none;" role="alert" aria-atomic="true" aria-live="polite" tabindex="3"></div> </div> </fieldset> </div> <div id="subItemsGroup"> <label id="headerTextLbl2"> Label with headertext </label> <fieldset aria-labelledby="headerTextLbl2"> <div id="selectionGroup2"> <label id="instructionLbl2">Select no to generate the error message</label> <table id="radioBtnTable2"> <tbody> <tr> <td> <label for="button:conf:3">Yes</label> <div class="ui-radiobutton ui-widget"> <div class="ui-helper-hidden-accessible"> <input tabindex="4" id="button:conf:3" name="button:conf:2" type="radio" value="false" onchange="var errorDiv = document.getElementById('lblErr2');while(errorDiv.hasChildNodes()){errorDiv.removeChild(errorDiv.lastChild);}"> </input> </div> </div> </td> <td> <label for="button:conf:4">No</label> <div class="ui-radiobutton ui-widget"> <div class="ui-helper-hidden-accessible"> <input tabindex="5" id="button:conf:4" name="button:conf:2" type="radio" value="false" onchange="var errorDiv = document.getElementById('lblErr2');errorDiv.style.display = 'block';var newDiv = document.createElement('div');var spanOne = document.createElement('span');spanOne.classList.add('ui-message-error-icon');var spanTwo = document.createElement('span');spanTwo.classList.add('ui-message-error-detail');var errMsg = document.createTextNode('Very long error message with special red font, details, paragraphs and recovery suggestion is displayed here');spanTwo.appendChild(errMsg);newDiv.appendChild(spanOne);newDiv.appendChild(spanTwo);errorDiv.appendChild(newDiv);"> </input> </div> </div> </td> </tr> </tbody> </table> <div id="lblErr2" style="display: none;" role="alert" aria-atomic="true" aria-live="polite" tabindex="6"></div> </div> </fieldset> </div> </div> </body> </html>

The JavaScript code which adds the error message. I added it to the onChange of the radio buttons:

 var errorDiv = document.getElementById('lblErr'); var newDiv = document.createElement('div'); var spanOne = document.createElement('span'); spanOne.classList.add('ui-message-error-icon'); var spanTwo = document.createElement('span'); spanTwo.classList.add('ui-message-error-detail'); var errMsg = document.createTextNode('Very long error message with special red font, details, paragraphs and recovery suggestion is displayed here'); spanTwo.appendChild(errMsg); newDiv.appendChild(spanOne); newDiv.appendChild(spanTwo); errorDiv.appendChild(newDiv);

This is an extracted and simplified version of our production HTML / JS. In production there are 5 to 6 of these selections one below the other and it is embedded into a greater HTML structure (with multiple parent divs which also have navigation elements and other stuff).

This HTML has a problem in combination with Google Chrome and an NVDA screen reader. In production when selecting the "No" selection the error message is added to the HTML, but no error message is read at all by NVDA. The same case in Firefox causes NVDA to read "alert ...".

The following section has been edited, please see edit below.

This reduced demonstration snippet behaves slightly different. Here Firefox reads the error message twice. Once only the messagetext and then the second time "alert" and then the message text. Chrome reads it only once and omits the second message starting with "alert". I only want it to read "alert ..." in both browsers.

The span and div construction surrounding the error messages is the same in production and in my snippet.

My question is: Why does NVDA not read "alert ..." when the message is added in Chrome? Is this a problem with the HTML or Chrome or NVDA? Can I fix it by making a non-breaking change to the HTML?

Edit: I now edited the HTML / JS so that it does not read any error message in Chrome at all, while it still reads it in Firefox. What changed is that the divs lblErr/lblErr2 now start out with a "display: none" style attribute, even though I remove it, before adding the error message. So it appears that Chrome / NVDA ignores modifications to divs, which start out with "display: none". Is this according to specification or is this a bug in Chrome?

Whether the screen reader says the actual word "alert" is a choice for the screen reader and browser combination. You can't rely on the word being announced. If you absolutely need it announced, then it should be part of your message.

The alert spec says:

"If the operating system allows, the user agent SHOULD fire a system alert event through the accessibility API"

Note that "SHOULD" does not mean "MUST". The definition of "should" is in rfc2119 and says:

"3. SHOULD This word, or the adjective "RECOMMENDED", mean that there may exist valid reasons in particular circumstances to ignore a particular item, but the full implications must be understood and carefully weighed before choosing a different course."

That is, SHOULD means it's encouraged but not required. So looping back around, the announcement of "alert" (via posting an alert system event) is recommended but not required.

So if your main question is how to get the word "alert" announced with all screen readers on all browsers on all platforms (PC, Mac, mobile), then you'd need to code the word directly in your error message. The word "alert" doesn't have to be visible on the screen but would have to be injected into a live region.

Also note that role="alert" gives you an implicit aria-live="assertive" and aria-atomic="true" so you don't need to specify those attributes. In your case, you are overriding the implicit aria-live="assertive" and specifically setting aria-live="polite" . It shouldn't hurt anything by doing so but you are defeating the purpose of using an alert role.

Whether a screen reader announces the actual message once or twice is a screen reader decision. On Firefox, I did hear the error message announced twice, once with "alert" in front of it and once without it. On Chrome, I only heard it once but it didn't say "alert". But on both browsers, the message was announced, which is the purpose of live regions.

You mentioned in your actual production code, nothing is announced on Chrome/NVDA. That would be strange. I've never had a case where I used aria-live and the message is not announced. I can only comment on the sample code you posted.

As I already mentioned in the edit section of my question, the core problem was that the div where I add the error message to with JavaScript has an initial display style attribute set to "none". It is also initially empty.

 <div id="lblErr" style="display: none;" role="alert" aria-atomic="true" aria-live="polite" tabindex="3"></div>

With this setup Google Chrome + NVDA does not read the dynamically added error message.

Once I remove the initial display style or change it to something else Google Chrome + NVDA starts reading the dynamically added error message.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM