Search topics
Old prices and removed words shown only by a strike-through
A shop's sale price draws the old price with a line through it in CSS, so a screen reader reads "$40, $28" with nothing to say which price is charged.
text-decoration: line-through; The problem
Screen reader users and people using read-aloud tools hear two prices for one product, with nothing to say which one they will pay.
A shop's product list shows a linen tote on sale. Under its name, $40 is drawn small and grey with a line through it, and $28 sits beside it in bold. Anyone who can see the card knows at once that the tote was $40 and is now $28.
A screen reader user moving through the list hears "Linen tote, $40, $28". The line through $40 is drawn by CSS and isn't part of the text, so both prices arrive alike. The next product, an enamel mug, is read as "Enamel mug, $18", so the first card simply has two prices, and only a guess, or adding it to the basket, says which one applies.
Success criterion 1.3.1, Info and Relationships, is level A. Information that the presentation conveys, such as which price is the old one, must also be determinable from the code or available in the text. W3C's failure F2 describes exactly this: a change in how text looks carries meaning, with no markup or text to carry it too.
The line-through is a CSS text decoration, not markup. In Chromium's accessibility tree, a span with text-decoration: line-through holding "$40" is plain text, the same as "$28" beside it. The line is passed on only as text formatting, as bold is, and NVDA, for one, doesn't report font attributes such as strikethrough at its default settings. A screen reader can only read what it is given. W3C's sufficient technique G117 is to convey the same information in text, and that is what the first two fixes here do.
Online shoppers compare prices on the list page, not only in the basket. When the sale is on the product card and nowhere else, the card is where the difference has to be heard.
2 of 10 groups affected
- No vision (affected)
- Low vision (not affected)
- Colour vision (not affected)
- No hearing (not affected)
- Hard of hearing (not affected)
- No speech (not affected)
- Motor (not affected)
- Reach, strength (not affected)
- Cognitive (affected)
- Seizures (not affected)
- Without vision A screen reader reads the text of the card, "Linen tote, $40, $28", and the line through $40 isn't part of it, so there is nothing to say which price is the sale one.
- Limited language, cognitive and learning abilities People who use a read-aloud tool to help with reading hear the same two prices; and a line through a number means "no longer" only to someone who knows the convention.
The HTML is valid, the grey of the old price has enough contrast, and axe has no rule for text decoration. EaseWeb's audit reports a price drawn with a line through it by CSS alone, with no word around it, shown or hidden, that says it is the old one (ew:struck-price-not-marked). It recognises prices by their currency, so it leaves struck-through to-do items alone, and it can't tell whether other styling, such as bold, colour or a highlight, carries a meaning that needs words.
Try it
Which tote price will you pay? Read what a screen reader says, then turn styles off.
The line through $40 is drawn by CSS. Does anything else say it is the old price?
Broken Can you fix this?
Linen tote
$40 $28
-
Enamel mug
$18
Reading the list, a screen reader says:
- Linen tote, $40, $28
- Enamel mug, $18
The fix
Put the meaning of the line in words: was and now, shown or visually hidden.
- 1Never let a line-through, a colour or a weight be the only thing that says what text means.
- 2Say which price was, and which is now, in words that are read aloud.
- 3Use s for an old price and del and ins for edits, as well as the words, not instead of them.
<li class="product"> <img src="linen-tote.jpg" alt=""> <h3>Linen tote</h3> <p class="price"> <span class="old">$40</span> <span class="now">$28</span> </p></li>Write was and now on the page
<li class="product"> <img src="linen-tote.jpg" alt=""> <h3>Linen tote</h3> <p class="price"> Was <span class="old">$40</span> Now <span class="now">$28</span> </p></li>Why this fix: Say it in words, not only in the styling
The line is only in the CSS, so the text of the price is "$40 $28". Nothing in the markup or the words says which of the two is the old one.
Two short words say what the line says. A screen reader reads "Was $40, Now $28", a read-aloud tool reads the same, and a sighted shopper who doesn't know what the line means reads it too. The line stays, so the card looks much as it did.
All three put the meaning somewhere other than the styling. Use the visible words: they give every reader the same information, including people who see the line but don't know what it means, for the cost of two short words. Use hidden words when the design really can't take them; screen readers get the same result. Add s to either if you like, but don't rely on it alone, since its effect depends on the screen reader.
Use s for a price that is no longer accurate, and del and ins for edits to a document, such as tracked changes or a suggested rewrite. They are different things: del says the text was removed, s that it no longer applies. Tracked changes have the same problem as prices, twice over: read aloud, the removed and the added words run together. Put hidden words such as "removed:" and "added:" at each change, as the tracked-changes sample does in the design ideas of AI rewrite buttons that replace text with no preview or undo.
Don't carry the words in an aria-label on the p or a span. Those elements can't be named, and many screen readers skip the label; see aria-label on divs and spans that screen readers often skip.
When the whole card is one link, the link's name is made of its text, so it includes the prices. The words then become part of the name, "Linen tote, Was $40, Now $28", which is what you want.
Keep the old price readable. Grey for the old price is fine at 4.5:1 or more: #6b6f7b on white is 5.02:1. A grey below 4.5:1 fails on its own terms; see low-contrast text on brand colours, photos and hover states.
In a list of many products, write the words the same way every time, from one price component, so a screen reader user hears one pattern.
Design ideas
A sale can look sharp and still be read out right.
Four more ways to show the old price or an edit, and two fashionable ones that fail. Each sample says in its note what a screen reader reads for it.
In the design file
- Write a word beside every old price, such as Was, Regular price or 通常価格. If it can’t show, note it in the file to be built as hidden text.
- Keep the old price at 4.5:1 or more against its background, and write the ratio beside its grey.
- For edits, draw removed words struck through and added words underlined, and name both in words for screen readers.
- Draw the price block once, as a component with its words, so every card says it the same way.
Passes
- Small “Was” label over the price A quiet capital label sits over the old price, struck through in #6b6f7b (5.02:1), and the new price stands large under it. Read as “Was $40, $28”.
Rule of thumb: Say it in words, not only in the styling
- “Save $12” pill A green pill (6.49:1) says the saving, and the old price is written out as “was $40” beside it, with no line needed. Read as “$28, Save $12, was $40”.
Rule of thumb: Say it in words, not only in the styling
- “Regular price” on a line of its own The sale price leads in red (6.57:1), and the regular price follows on its own line, in words and without a line through it. Calm, and nothing to decode.
Rule of thumb: Say it in words, not only in the styling
You can return any item within
removed: 14added: 30 days of delivery for a full refund.Suggested edits, struck and underlined, with hidden words Removed words struck through on pale red (6.44:1), added words underlined on pale green (6.49:1), and hidden “removed:” and “added:” before each, so the suggested edit to a returns policy is read as “within removed: 14 added: 30 days”.See also: AI rewrite buttons that replace text with no preview or undo
Fails
- Old price slashed through at an angleWCAG 1.3.1 A diagonal slash drawn by CSS looks bolder than a line-through, but it is decoration all the same: the text is read as “$40, $28”, with nothing to say which is old.
You can return any item within 14 30 days of delivery for a full refund.
Suggested edits shown by tint aloneWCAG 1.3.1 Soft red and green backgrounds with no strike-through, no underline and no words. The edit is read as “within 14 30 days”; and with no line, it also leaves people who can’t tell red from green guessing.
Verify the fix
3 checks, no mouse.
Test with: Screen reader, Styles off
Record the OS, browser and assistive-technology versions, the build, the date, and the actual result of each step. Repeat after the price component or the shop's theme changes.
Limits
This is a starting pattern, not a guarantee for every page. The example is an old price; the same goes for other text whose look carries meaning, such as a highlight that marks a match, bold that marks the one important word, or text in red that says something is wrong: say it in words as well. A blockquote used only to indent text, so that it is announced as a quotation it isn't, is another failure of the same criterion (F43), not covered here. Test the product list, the product page and the basket with the people and tools your users rely on.
This is a recreated teaching example, not a finding about a named client. The code is a starting pattern: test it in your own product. No completed assistive-technology test is claimed here.
Keep this fixed as your code changes.
Turn guides like this into rules your coding agents and CI follow, then have the result retested with a keyboard and screen readers.