TJKDesign: Home Page

ez-css Putting the 'less' in table-less layouts. css-101 logo
Bookmark this article at these sites:

This technique is very versatile. Make sure you read the entire article to find out about the many different ways to implement the method. Also, I wrote four new articles based on this solution:

Image Placement vs. Image Replacement (FIR)

What is FIR?

FIR is a standards-compliant technique that uses stylesheets and ordinary HTML to provide a visible image, usually consisting of text. The designer specifies, through CSS, that the image will display in most cases; if it should not display for some reason, the underlying structural HTML markup is supposed to take its place.

Joe Clark: Facts and Opinion About Fahrner Image Replacement

After spending some time reading about FIR, I thought it would be interesting to turn the debate on its head by reverting to the discarded <img /> element.
Please read on...

FIR factor

The various successors to the original Fahrner Image Replacement method have explored many different techniques. It seems that no stone has been left unturned by designers attempting to enhance the method. To achieve this goal they have tried all sorts of CSS attributes (display, overflow, text-indent, visibility, z-index, line-height), and structural hacks (empty span element). They even gave JavaScript (JS) a shot.

In my experience, however, all these techniques fail on some level with regard to various User Agents and their individual specificities:

  • Old browsers
  • Text browsers
  • Screen readers
  • JS-challenged browsers

Moreover, browser configurations play a role:

  • images ON / CSS OFF
  • images OFF / CSS ON
  • images OFF / CSS OFF
  • large font-size

Whichever technique is employed it must be flexible enough to deal with the following:

  1. Show the image or, at the very least, the text it is meant to replace in any visual browser
  2. Make that text accessible by assistive devices (screen readers)

Whichever technique is employed, it must also successfully address these additional challenges:

  1. Avoid the simultaneous rendering of both text and image.
  2. Prevent text from leakage visibility regardless of user's text-size settings (e.g. text appearing beneath an image).
  3. Do so without use of "hacks".

I believe that I have found a plain and simple solution that not only addresses the points above, but further challenges as well, by using the very element everyone was trying to avoid in the first place - the <img /> element!

FIR less

The primary purpose of any Image Replacement technique is, as the name suggests, to replace text with an image to convey the same information, but in an aesthetically pleasing way.

Unfortunately, because most of these techniques rely on background images, the text ends up on top of the "stack". The challenge then becomes to somehow make that text disappear.

If we start by placing an image before text in a heading:

<h1><img src="/img/helloworld.gif" alt="" />Hello World</h1>

Then, this simple CSS rule could make the text portion vanish.

h1 img {position:absolute}

See example 1

Challenges we overcame:

  • The text is hidden, but accessible by screen readers as well as in visual browsers in which images have been disabled.

Challenges remaining:

  • Depending upon text-size, the text in the heading may "peek out" from beneath the image.
  • In visual browsers not using Styles Sheets image and text appear side by side.
  • Netscape 6 places the image below the text.

Next step:

Ensure that the text always remains within the boundaries of the image (NN6 included) and below the image (Opera 6).

Use the overflow, z-index and position properties keeping the exact same markup.

h1 {height:28px;width:207px;overflow:hidden;position:relative}
h1 img {z-index:1;position:absolute;top:0;left:0}

The width and height here are set to match the dimensions of the image.

The 2 position declarations are for NN6 (the first one is to make sure the browser positions the image in relation to the heading). Unfortunately, fixing NN6 breaks Opera 6 (it changes the stack order and places the text on top of the image). So we're using z-index to make sure Opera 6 hides the text behind the image. Of course, this last fix comes with its own issue, because it also makes this browser drop the image by a few pixels in this more advanced solution.

See example 2

Challenges we overcame:

  • No matter how large the text-size is set in the browser, the text now stays below the image and within the limits of its boundaries.

Challenges remaining:

  • If the image doesn't show for any reason, the text may appear to be "cut-off", depending on the user's preference regarding text-size.
  • If the document is unstyled, both elements (image and text) still appear in visual browsers.
  • MSIE Mac v.5 does not show anything.

FIR no more!

Next steps:

If we keep moving away from the original method, we can actually resolve all issues at once.

We now use a transparent image (using a 1px * 1px image gives the element a minuscule footprint):

<h1><img src="/img/clear.gif" alt="" />Hello World</h1>

There is no longer a need to style the heading. Instead, we can focus on the image itself. The whole concept involves using the boundaries of the image as a flexible "window" to frame a rather large background image.

Based on that above, this is our new CSS rules:

h1 {
	position:relative;
	font-size:1em
}
h1 img {
	z-index:1;	
	position:absolute;
	top:0;
	left:0;
	width:538px;
	height:1.7em;
	min-height:28px;
	background:transparent url(/img/helloworld.gif) no-repeat;
	border:1px dotted red
}

How does it work? :

  • pixels are used for the width attribute value (I'm setting this value to match the size of the actual image). Why that value? Simply because there is no advantage to making the "real" image bigger than the background image that it contains. Remember, there is no background color (see below) that would come to fill the gap.
  • em (a relative unit) is used for the height attribute value. I'm using 16px for 1em. So here, 1.7em is approximately the same value as the height of the usable part of the image (which is roughly 28px high).
  • a min-height value is set for modern browsers (MSIE is not a modern browser). Because we've used a relative unit for the height, we need to prevent our flexible "image" from becoming smaller than the image it is "hosting" (in case the user decreases the text-size).
  • transparent is our only option regarding background color. Keep in mind that this image is on top of our text. If the image does not show up, its background color would hide that text.
  • border is used here only to help you understand what's going on in relation to text-size (increase/decrease).
  • font-size is used to size down the text in the heading.

We have set the dimensions for the image to create a flexible window. The width is fixed to prevent a few potential problems such as the spawning of a horizontal scrollbar or having to use min-width (that MSIE does not support). As the height is fluid, it will adjust gradually to match any change in text-size.

Because the image we used is 538px by 295px, the text in our heading will need to be larger than these dimensions before appearing from beneath the image.

If you do not care for Opera 6, do not hesitate to omit the z-index declaration.

See example 3

The black dotted border around the image(s) in the example pages is to give a better idea of the size of the picture that is used, while the red dotted border is to show the boundaries of the image element that is sized through the CSS rule.

Challenges we overcame:

  • When images are disabled, the text does not appear cut-off, regardless of text-size.
  • If the document is unstyled, only the text appears.
  • This new approach works in MSIE 5 Mac.

Do you want an anchor with that?

If you include an anchor in the heading, then there is no need for an image element. This would be your (X)HTML markup:

<h1><a title="Take me home!" href="/"></a>Company Name</h1>

CSS declarations are identicals, only the selectors change:

h1 {position:relative}
h1 a {
	z-index:1;	
	position:absolute;
	top:0;
	left:0;
	width:538px;
	height:1.7em;
	min-height:28px;
	background:transparent url(/img/helloworld.gif) no-repeat;
	border:1px dotted red;
	font-size:1em
}

Give it a try: example 4

And think of named anchors too:

<h1><a id="topOfPage" name="topOfPage"></a>Company Name</h1>

In my opinion the above solution is perfect for an image at the very top of a document. And this is extra clean markup that should make every standards zealot out there happy.

Final check:

I believe this method resolves many "problems":

  • There are no longer accessibility or usability issues with:
    • screen readers
    • old browsers
    • JS-challenged browsers
    • visual browsers with CSS off
    • visual browsers with Images off
    • visual browsers with CSS and Images off
    • visual browsers with CSS off, but images on
    • visual browsers with CSS on, but images off
    • high-contrast styles sheets
    • Windows high constrast mode optimization
  • In visual browsers, either the text or the image appears, never both together.
    • If the text appears, it is responsive to client-side text-size settings
    • If the image appears, it is never cut-off
  • In visual browsers, to some extent, the text stays behind the image regardless of the user's settings regarding text-size
  • There are fewer SEO implications

As we are using an <img /> element, we have access to the title and alt attributes. By leaving out the title attribute and setting an empty value for alt we avoid some redundant information for users of screen readers when the document is read aloud. But, nonetheless, I am sure some people would find a good reason to use these attributes' values :-)

When using a real image (vs. a background image) the user doesn't experience flickering in MSIE when hovering over the element.

It is important to note that this method uses all the necessary elements. In short, it does not rely on any structural hack.

Pushing the envelope

Images rollovers:
An anchor is all that we need (no image element there). See example 4
It's a post from Richard Czeiger on the CSS-D list that gave me the idea.
Making the image scalable like the sIFR method does:
Slightly limited, but see example 5.

With this method, one can style a group of elements without having to rely on div or class selectors. This is possible because the path to the image is part of the markup, not an attribute's value in the Stylesheet.

Another advantage of this technique is that the images, like in example 5, may be printed.

Replacing one image with another in media-specific instances.

Aaron Gustafson came up with a nice little trick that can also be used with the method discussed here. It is called iIR, it stands for img Image Replacement.

More on FIR

For further reading on the subject of FIR, visit the following URIs:

Techniques that go way beyond the call

2 amazing techniques to help you go "dynamic":