Accessible Text Replacement

Following my post regarding the SEO and accessibility issues invoked when using display:none, I am now going to address the text replacement scenario, since I believe this is the only situation where one would legitimately want to hide text from the unassisted visitor (reading visually) but not from a screen reader or search bot.

I am aware that this issue has been discussed at length elsewhere (see Mr. Johansson's article and related posts) but I wanted to focus particularly on text replacement in titles (h1, h2 etc.) and to offer advice on maintaining semantic HTML and responsiveness to layout. I am also aware that, after the dawn of the web font (and with the help of some text-shadow or other such CSS3 enhancements), you have the option of achieving a variety of attractive typographic effects that do not require images and are implicity accessible methods.

What is text replacement?

Text replacement is the substitution of 'real text' for a visual approximation of it. By 'real text', I mean text that appears in the markup as a 'text node' within an element …

<h1>I am an important text node</h1>

...and by 'visual approximation', I mean an image that visually emulates the characters that make up the intended word or phrase.

Since screen readers and search engine bots have trouble interpreting the intended lexical content of images, it is considered wise to also provide some 'real' text in order to satisfy the requirements of these technologies. This is particularly important regarding headings because they carry so much semantic weight. We would like to hide this additional text from the display because the typical user would otherwise see the same wording twice. The question is: how?

I shall now present different text replacement methods compared against their output in the Fangs screen reader emulator for Firefox. I have tried to order these methods from 'awful' to 'better'.

Method 1: A span set to display:none

<h2>
     <img src="heading_text.jpg" />
     <span style="display:none">Heading Text</span>
</h2>
<p>The paragraph starts here...</p>
Heading level two, The paragraph starts here...
Fangs screenshot

Verdict: As my previous post states, screen readers will usually ignore content that has been styled with display:none because their job is to emulate the experience of reading visually and one cannot read what one cannot see. The Fangs output foregoes the heading text so this method is absolutely useless.

Method 2: The 'alt' attribute

<h2>
     <img src="heading_text.jpg" alt="Heading Text" />
</h2>
<p>The paragraph starts here...</p>
Heading level two, Graphic: Heading Text, The paragraph starts here...
Fangs screenshot

Verdict: The heading text is clearly present via the alt attribute but is preceded by the 'graphic' flag. We don't want users who see the image to apprehend it as one so we certainly don't want this secret read aloud to the visually impaired. Text in a heading derived from an alt attribute is inadequate and semantically incorrect. As the Firefox Accessibility Extension warns:

"Each subheading (h2 … h6) should have text content exclusive of the alt text of any img element it contains"

Firefox Accessibility Extension

Method 3: The span which has no height

<h2>
     <img src="heading_text.jpg" />
     <span style="display:block; height:0; overflow:hidden">Heading Text</span>
</h2>
<p>The paragraph starts here...</p>
Heading level two, Heading Text, The paragraph starts here...
Fangs screenshot

Verdict: The empty alt attribute suppresses validation errors as well as removing the 'graphic' flag. At the same time, the esoteric method for hiding the span element is undetected by the Fangs emulator and the heading text is present. Unlike the image's alt attribute, the span is a legitimate child of the heading and, because it is semantically inert, there is no cause for it to be flagged by the reader.

Method 4: The Phark Method Without CSS images

<h2 style="text-indent:-99999px">
     Heading Text
     <img src="heading_text.jpg" alt="" />
</h2>
<p>The paragraph starts here...<p>
Heading level two, Heading Text, The paragraph starts here...
Fangs screenshot

Verdict: Identical to the Fangs output of Method 3 but dispenses with the extraneous span. This method differs from typical implementations of the Phark Method (mentioned in this excellent round-up) in that it does not rely on a background image. Although removing the image tag makes for simpler markup, using a background image makes responsive design more difficult:

Whilst real text will wrap at smaller screen sizes and images can be set to width:100% (allowing them to scale according their parent element's width), background images are simply not malleable, necessitating headings with fixed, pixel-based dimensions to accomodate the image. This caveat applies to the Leahy and Langridge method too.

It might be possible to create CSS sprites containing versions of the heading at different sizes and change the background-position according to media queries. I did this once, then the client changed their mind about the wording …

Update: The Phark Method works by drawing a giant box to the left of the content's origin. This is said to be detrimental to performance. For this reason, you could deem Method 3 preferable.

CSS on, images off

I have not mentioned the thorny issue of browsing with CSS on but images off and the 'Phark without CSS images' method certainly fails to display the heading text in this scenario. Whilst this is a bandwidth before it's an accessibility concern, it is possible to fix it.

One can use javascript to detect whether the context allows images or not and only apply the text-indent if images are present, making it applicable. This article offers just such a solution. It is rather old and you should be wary of the 'document.write', but it doesn't require the jQuery library which saves us a hefty http response. If your connection is likely to struggle with images, it will have a hard time loading large javascript libraries as well.