If I have the following HTML:
<html>
<body>
<h2>
Buy our awesome product!
</h2>
</body>
</html>
... Apple VoiceOver will say:
"heading level 2, Buy our awesome product"
Which is great, and expected.
However, if I change it to this:
<html>
<body>
<h2>
Buy our <i>awesome</i> product!
</h2>
</body>
</html>
Apple VoiceOver will say:
"heading level 2, 3 items, Buy our... awesome... product... Buy our... awesome... product"
(adds "3 items", pauses between elements, and critically, repeats the heading)
I'm expecting VoiceOver to just say it exactly the same way as it does without the italics.
Of course I'd love to keep it from saying "3 items" and remove the pauses, but the main concern is that it repeats the heading. I've tried using <span>, using classes, and enclosing everything in a <div> as others have suggested on similar questions, but nothing I've tried so far seems to prevent the repeating. I feel like I must be missing something simple, right? Or is there really no way to style parts of a heading without glitching VoiceOver?
Possibly relevant or helpful, I've discovered this issue only seems to come up for headings. If I run VoiceOver on the following code, it's just read once as if the italics or separate elements weren't there at all:
<p>
Buy our <i>awesome</i> product!
</p>
This issue occurs for me on both Chrome and Safari. I have not tested other browsers.
If at all possible I would prefer an HTML/CSS solution and avoid using a javascript hack, as I am not a javascript pro.
Disclosures:
- Yes, I'm using styling beyond
<i>to specifically style certain elements of my headings, but the above is a much simpler example and produces the same results. - My problem page is in fact running some scripts like Google Tag Manager and jquery, but even if I create a completely naked test page with the above HTML I get exactly the same results.
In my opinion, this is a VoiceOver bug, and not one that is easy to work around.
Last year, I ran various test cases with VoiceOver and found that the only approach that avoids the experience you describe in VoiceOver was to use
role="text". This would stop VoiceOver from treating each child element as a separate heading as shown in this demo and explanation by Patrick H Lauke on YouTube. For example:When
role="text"(unofficial spec) is applied to a container element, it would force VoiceOver to recalculate the accessible name of the heading element, reducing it to a single element. This worked on macOS and iOS.I also tested using
aria-labelto try to hack around these issues in VoiceOver, but found no suitable solution.However, it seems that VoiceOver now has a more consistent experience across each of the techniques I tested. While VoiceOver now reads the headings as a single announcement, it also always announces that there are multiple items within the element. I'm in the process of testing this further.
You may like to try one of the techniques I used in my test cases, but use with caution. However, it may be that there is now nothing you can use as a workaround.