Strikethrough <s> is an HTML element to indicate text that is crossed out – usually indicated visually with a line through the middle of the text. The W3C definition is:
The s element represents contents that are no longer accurate or no longer relevant.
On e-commerce websites, a strikethrough element is often used to indicate a price is no longer valid and often has a reduced price next to it.
The problem is that most screen readers don’t output the strikethrough semantics. This can be very problematic to the blind user since they won’t know which price is valid. Most in-line semantic elements such as <em> and <mark> are not conveyed to screen readers actually. For more on that, reference the article Screen Readers support for text level HTML semantics by TPGi.
Let’s examine four test cases and the level of support. Note that the strikethrough element is mapped to the deletion ARIA role which we’ll use in test Scenario 2.
Test Cases
Four code scenarios were tested against 6 screen reader/browser/OS combinations including VoiceOver, NVDA, JAWS, and TalkBack. The actual test cases used are in the second portion of the CodePen Negative number and strikethru tests.
Scenario 1: strikethrough element only
Price: $200 $100
Price: <s>$200</s> $100
The plain old semantic HTML—an S element around the text. This is obviously the ideal code, but support isn’t quite there yet. Only NVDA and TalkBack passed.
Scenario 2: strikethrough with ARIA ‘deletion’ role
Price: $200 $100
Price: <s role="deletion">$200</s> $100
This is similar to Scenario 1, but with the addition of role=”deletion”. The test results were similar to without the role. The only difference is that VoiceOver on iOS also passed.
Scenario 3: strikethrough with visually hidden text
Price: original price$200 sale price$100
Price: <span class="visually-hidden">original price</span><s>$200</s> <span class="visually-hidden">sale price</span>$100
This test case uses the old school technique of visually hiding text via CSS. “Original price” outputs before the price with the strikethrough, and “Sale price” outputs before the valid price.
All screen readers passed this scenario.
Scenario 4: strikethrough with visually hidden pseudo-content
Price: $200 $100
Price: <s>$200</s> $100
#pseudo s::before {
content: " [start of stricken text] ";
}
#pseudo s::after {
content: " [end stricken text] ";
}
#pseudo s::before,
#pseudo s::after {
clip-path: inset(100%);
clip: rect(1px, 1px, 1px, 1px);
height: 1px;
width: 1px;
overflow: hidden;
position: absolute;
white-space: nowrap;
}
The fourth test case has the same HTML has Scenario 1. But then applies a brilliant method by Adrian Roselli introduced in 2017 in the article Tweaking Text Level Styles. Pseudo-content (creating a textual phrase via CSS) is used to indicate when the strikethrough starts and ends.
There are a couple issues to mention with this approach:
- Since NVDA now supports the strikethrough tag, it indicates the semantics twice — both the S element semantics (“deleted”) and the pseudo-content (“start of stricken text”) which creates ambiguity for the user.
- Oddly, the double semantics is not conveyed by TalkBack which did pass the previous three scenarios.
- With JAWS, the output is broken up with multiple stops which makes it difficult to follow. (Changing the brackets to parentheses might help.)
This technique technically works for all screen readers, but the user experience is very confusing for NVDA users.
Test Results
Does screen reader output “deleted”, “stricken”, or similar?
iOS + Safari + VO | MacOS + Safari + VO | Android + Chrome + TalkBack | Win + Chrome + NVDA | Win + Firefox + NVDA | Win + Chrome + JAWS | |
---|---|---|---|---|---|---|
Scenario 1 | No | No | Yes | Yes | Yes | No |
Scenario 2 | Yes | No | Yes | Yes | Yes | No |
Scenario 3 | Yes | Yes | Yes | Yes | Yes | Yes |
Scenario 4 | Yes | Yes | Yes | Yes | Yes | Yes |
Conclusion
NVDA has the best support for <s>, the strikethrough element. For now, to best support screen readers overall, we should continue to use Scenario 3 — strikethrough with visually hidden text — to programmatically convey strikethrough semantics. Doing so will ensure that everyone understands strikethrough semantics while browsing the web which often means knowing the correct price of a product or service.
Further reading
- Ensuring negative numbers are available for everyone via Deque Systems
- How To Use Inline-level and Block-level Elements in HTML by DigitalOcean
8 replies on “Strikethrough Accessibility”
How about the `del` element, does Android + Chrome + TalkBack support it? Or a `span` with `role=”deletion”`? Since you found TalkBack announces `s` elements, I hope it does the same for `del`.
In the text level HTML semantics TPGi post you linked to, Steve Faulkner documented `del` being announced by JAWS, NVDA, and iOS VoiceOver but his table didn’t include any information about TalkBack.
I reviewed some text semantics recently and can confirm DEL works in Talkback – we’re using that instead of S at my company (the screen readers I reviewed do not have different announcements for S vs DEL)
https://codepen.io/ourboldhero/full/NWezZpz
One gotcha to watch out for here is that relying on pseudo elements as per option 4 can be considered a failure of WCAG F87.
Another point that Mr Roselli has opined upon. https://adrianroselli.com/2019/02/f87-css-generated-content-and-wcag-conformance.html
I also have found that with the pseudo-element approach, my VoiceOver sometimes reads the deletion start and end sequentially instead of before and after the text it is wrapping, which makes it unusable as an approach.
[…] Make things accessible […]
[…] Make things accessible […]
Thanks for the great article! Just fyi, it seems like the “visually-hidden” class in the 3rd scenario is now missing in the article’s css, breaking the example
Thanks! Fixed. (I added .visually-hidden to the blog CSS.)