My thoughts about the latest Image Replacement techniques

This article was first published on css-101.org (04-05-2012).

If you’re in the business of building web sites, chances are that you heard about the latest Image Replacement (IR) techniques:

As far as I know, there has been nothing new in this field since 2010, when @necolas published “Improved NIR” based on the Nash Image Replacement method which was a departure from relying on background images - an idea I introduced with my own technique in 2005.

Replacing the -9999px hack

This first article, by Jeffrey Zeldman, claims to offer a better method than the famous Phark’s Accessible Image Replacement technique. Better because…

[…] despite its enduring popularity, Phark has drawbacks of its own: chiefly, a performance hit caused by the need to draw a giant 9999px box offscreen. (Yes, the browser really does this.)http://www.zeldman.com/2012/03/01/replacing-the-9999px-hack-new-image-replacement/

The snippet from Scott Kellum, which is said to improve upon the original method looks like this:

.hide-text {
    text-indent: 100%;
    white-space: nowrap;
    overflow: hidden;
}

There is no formal explanation about the first declaration, so the best I can do is guess the author’s intent: the 100% value for text-indent is meant to move the text just outside of the box, to its right edge(?).

This is how I’d think most people would understand that rule. Unfortunately, this is not how things work. When using *percentages, the indentation is not related to the container but to the containing block, which is an ancestor.

What does that mean? It means that styling alone does not tell us where the text will be displayed in relation to its container, simply because that container is not the box used to compute the 100% value.

The box could well be 200 pixel wide with its text positioned outside the viewport which would create a box not as gigantic as -9999px alone would paint, but an oversized box nonetheless.

Even worse, this technique does not guarantee that the text will be hidden. That text could well be in plain view depending on the styling of other boxes, like the fiddle below demonstrates (check the styling for yourself):

So what gives?

The magic bullet here is overflow:hidden - that’s what does the heavy lifting. This declaration will hide the text as long as that text is positioned outside the padding box. What’s interesting though is that this styling is part of the original Phark method, which is:

#header {
    text-indent: -100em;
    overflow: hidden;
    background: url(sample-opaque.gif);
    height: 25px;
}

As you can see there is nothing wrong with Mike Rundle’s technique; what’s wrong is the fact that people adopted a different version:

#header {
    text-indent: -5000px;
    background: url(sample-opaque.gif);
    height: 25px;
}

According to mezzoblue, this was necessary because:

Phark Revisited: Further probing has revealed weaknesses with the previous one, revolving around scrollbars in Safari, and breakage in IE5.http://www.mezzoblue.com/tests/revised-image-replacement/

But as far as I know, these issues are obsolete. At least since 2009, when Patrick Lauke suggested that we should add overflow:hidden to links styled with negative text-indent. As the image below shows, it was to prevent some browsers (IE and Firefox) from creating a box that extended to the left edge of the viewport (the infamous giant box), around which the outline was painted.

Outline bleeding off to the left Outline bleeding off to the left (image from 24ways

It turns out that with his article on 24ways.com, Lauke resurrected the original Phark method which, in my opinion, is safer to use than the Kellum technique (see this fiddle).

In any case, if you really dislike the -9999px value in there, you could try something like this:

.move-it-to-the-left-but-not-as-far-as-9999px {
    text-indent: -500px; /* that should be enough */
    overflow: hidden;
    font: 10px monospace;
    letter-spacing: -10px;
}

Note that even if the above rule makes the string very small (via letter-spacing), we still need to use a value large enough to move the text away from the padding box.

Another CSS image replacement technique

This second technique is from Nicolas Gallagher; it was recently added to the HTML5 Boilerplate project. It looks like this:

.ir {
    font: 0/0 a;
    text-shadow: none;
    color: transparent;
}

I love the shorthand declaration in there (from BEM). I think it’s very clever. But that’s about all I like in this technique.

These are my concerns

SEO

If I recall, font-size:0 and color:transparent used to be known as black hat techniques. I don’t know enough about SEO, but I would not feel comfortable hiding text like this if that text contained keywords, or was Microformats data, or inside a link or heading…

Screen-reader

Nicolas’s article reports that…

Windows-Eyes has a bug that prevents the reading of text hidden using this method.http://nicolasgallagher.com/another-css-image-replacement-technique/

But as far as I know this is an assumption based on the fact that this screen-reader behaves differently than others. I asked on various channels what was the expected behavior according to the specification but did not receive any concise answer.

“in-box” styling

In my opinion, styling the text inside the box is not safe because of the cascade. User styles sheets and common practices may override the styling coming from this technique. For example, a simple rule like the one below may easily reveal the text:

CSS
#myBox p {
    font-size:1.1em;
    color:#555;
}
Markup
<div id="myBox">
    <p class="ir">Hide me</p>
    <p>Some more text</p>
    <p>Some more text</p>
    <p>Some more text</p>
</div>

And it is not future proof either as any style that the text would inherit could appear inside the box (i.e. text-outline). Something we can already verify with -webkit-text-stroke.

Conclusion

Before adopting an Image replacement technique for your everyday development, you should know that it is not because a solution exposes the text to screen-readers that it is deemed to be accessible. So when looking for an IR technique try to keep in mind that…

In short, it should be important to you to display the text in case the image does not show. The goal of any IR technique should be to mimic what the alt attribute does: showing the text when the image does not load.