Chris Coyier wrote a demo of what you can do with icon fonts and it’s rather compelling. Chris has included a rebuttal of the “oh yeah but it’s not accessible” argument but sadly his answer only addresses a fraction of the problem. So I’d like to expand on that.
Disclaimer: I know more about web accessibility than most CSS coders, but much less than accessibility experts. I’m writing this partly to get answers and feedback. :)
Accessibility is not (only) about screen readers
Most web developers who have heard about accessibility tend to think that accessible code is code that works decently in screen readers. Not quite. Screen readers are just one type of assistive technology (and more broadly one type of user agent). Some people will use other assistive technology, or they will use regular web browsers but use some of their features which we’re not used to design for.
Possible issues with negative
Chris used this HTML code as an example:
<a href="#" class="icon icon-replace icon-check">Check</a>
There is no accessibility issue with this HTML code (though if it’s a button rather than a hyperlink, using the button element would be better). But what about the CSS?
Chris does two things: generate a pseudo-element to show the icon, and hide the original text with a negative
text-indent (a technique that doesn’t hide the text from screen readers). Here’s a couple of situations where it could break:
- The stylesheet is applied, but the font file is not loaded or delayed (network issue) or not recognized (support issue). The text label is hidden, and what is displayed is sometimes a Unicode symbol (if the user’s system fonts support it), and most of the time a meaningless letter like a capital “B” or a lowercase “z”.
- The user asked their browser to always use their preferred font (e.g. a font designed for dyslexics), overriding the page’s styles. What gets displayed is either a Unicode symbol or a meaningless letter.
I’m probably forgetting a few use cases. Anyway, what Chris’ solution does is handle one such case: screen reader use. Basically, it’s an inaccessible solution that comes with an accessibility fix for one use case. Is that enough? I don’t know.
Going deeper: inaccessible by design
If we go back to Chris’ example, here’s what the resulting DOM looks like (pardon my pseudocode):
<a> <before>✔</before> <text>Check</code> </a>
Now compare it with this HTML construct:
<a> <img src="https://fvsch.com/articles/icon-font-a11y/check.png" alt="Check"> </a>
When we use the
img element, the user agent knows that the picture and the text are equivalent (and by default the picture is preferred). It’s able to show the picture, but also to replace it with the text for any sensible reason (e.g. user asked for this behavior, or the picture did not load).
When we use common image replacement techniques, including the smart ones, the user agent doesn’t know what’s the relation between the text content and a CSS pseudo-element or background. This is not even a “CSS is for decoration” issue. It’s a “your code lacks semantic information” issue, with two consequences:
- Browsers cannot offer options to users who need or want them.
- Browsers cannot react when something goes wrong (e.g. your background image or custom font doesn’t load over that unreliable 3G network).
When can I use CSS for icons ?
If you’re keeping a visible text label, and just want to add an icon next to it, by all means do use CSS backgrounds or an icon font.
Are there other semantic solutions for icons with no visible text ?
I’m not sure. Maybe something with SVG, maybe something with the
abbr element, but I wouldn’t bet on it.