CSS 3 Image Replacement
Since before the dawn of time, designers have wanted sexy fonts or images for headings, links and buttons on web pages. The adoption of @font-face
for CSS to use any font a designer specifies will take away some of the use cases. The time-honoured method of using img
in the source code, and using the alt
attribute to as a text alternative still works, of course, and very nice it is too, but some designers prefer to use CSS to replace text with an image.
There is a variety of image replacement techniques, but they all add a background image and then hide the text, usually by moving off the screen. They all suffer from restrictions: they can only be used with opaque images, or against flat colour, or they need extra span
s for style hooks. There's also the problem of people who surf with images off, which is quite common for those using phones whose web use is metered. They don't see the image, but don't see the text either.
Using the content
property
The CSS 3 content
property is experimentally supported by Opera and Safari. Firefox supports the CSS 2.1 spec when used with the :before
and :after
pseudo-elements and there is rudimentary support (so far) by IE 8 beta.
It allows you to "insert" text or an image into an element, over-writing the HTML content of the element.
So, for example, this code snippet will replace my name in the h1
with my blog logo:
h1 {content: url(bruce-logo.jpg);}
<h1>Bruce Lawson’s gorgeous blog</h1>
You can see it in action on this image replacement test page.
It's interesting to note how the browsers style this differently. To centre the logo, you need to style the h1
with text-align:center
, as if Opera centres the real text and then replaces it with the image. Safari will only centre the logo with margins, as if it replaces the text with a virtual img
tag, which is then impervious to text-align
.
What should browsers do if the image can't be shown?
I think, in any circumstance that a browser can't show an image, it should show the content of the element in the natural position for that text. That would ensure that this CSS 3 image replacement technique degrades well when CSS and images are off.
This behaviour would be similar to iframe
: "The information to be inserted inline is designated by the src attribute of this element. The contents of the iframe
element, on the other hand, should only be displayed by user agents that do not support frames or are configured not to display frames." In a similar way, html has a fallback mechanism for images and objects: when it can't show the image, it shows the alternate text.
Here's where the support for this image replacement mechanism gets experimental, even in the highly standards-compliant browsers. This is because the specification changed between CSS 2.1 and CSS 3.
CSS 2.1 said
If the user agent cannot display the resource it must either leave it out as if it were not specified or display some indication that the resource cannot be displayed. CSS2 spec
So the current "standard" says that it should either show the contents of the element (the actual text between the tags), which makes sense to me, or some sort of "image not found" icon, which seems to me to be the worst of all worlds. If a screenreader or a search robot gets the plain text, why not a user who has images switched off?
The CSS 3 spec allows you to set a series of fallbacks, much like when you set font-family
. So here, the browser will try to replace the header with a movie, then an animated gif if it can't find or display the movie, or a standard jpg if it can't find or display that gif, and if it can't render any of those, it will just show the contents of the element:
h1 {content: url(header.ogv), url(header.gif), url (header.jpg), contents; }
The spec says
If no alternatives exist, then 'none' is used as a final fallback...Thus to make an element fallback on its contents, you have to explicitly give 'contents' as a fallback. CSS 3 spec
To me, it's odd that anyone should want to display nothing instead of the content, let alone make it the default, but at least the new specification allows you to unambiguously tell the browser to display the contents of the element: it's not allowed to "choose" between the text and a "image not found" icon.
What do browsers do?
However, browser support is still experimental as the generated and replaced content module of CSS 3 is still susceptible to change. My no-images test page shows that Opera and Safari still have problems following the CSS 3 spec fully.
Conclusion
Once the CSS 3 spec is finalised and the browser support is solid, a foolproof way of doing image replacement will be available to us that is accessible to screenreaders and which degrades gracefully with CSS off and with images off.