Menu

The Vanishing Image: XHTML 2 Migration Issues

July 2, 2003

Mark Pilgrim

Mapping a Migration Path

I am not the world's greatest XHTML 2.0 fan. I initially gave up on it completely because of its intentional (and, in some cases, seemingly spiteful) backward incompatibility with XHTML 1. I was convinced that developers would need a migration path in order to adopt it, and there was no such migration path. This series is, in part, my own attempt to see how big a problem this backward incompatibility really is.

Why bother talking about a migration path at all? All the work I have seen so far in the XHTML 2.0 world has been about what it would be like to be there. Which makes sense, since it's not finished yet and the HTML Working Group is still hashing out the details. However, there has been a distressing lack of information about what it will take to get there from where we are now. Even assuming that where we are now is "valid XHTML 1, used properly" (a huge assumption for most sites), there is still no information about how to make the leap from there to XHTML 2.

Members of the HTML Working Group seem totally unconcerned with this. They have indicated publicly (on the www-html mailing list) that they see no need for a migration path from XHTML 1 to XHTML 2. XHTML 2 is not a replacement for XHTML 1, they say. XHTML 2 is only for new documents and applications built from scratch; no one will bother converting existing documents and applications.

However, experience has shown us that there is a natural demand for the latest and greatest, if only out of fear. Developers see "XHTML 2" and mistakenly assume that it is a replacement for "XHTML 1". And they fear that if they only know "XHTML 1", HR departments will soon start rejecting their resumes because they are filtering on "XHTML 2" (which probably is true; I mean, let's face it). Meanwhile, the HTML Working Group has done just about everything it can do to create confusion in the marketplace by giving XHTML 2 the same name as the language it's not replacing, the same MIME type, and the next major version number.

Looking even further ahead, it is important to note that XHTML 2 is the only W3C-approved markup language that is evolving. The HTML Working Group has stated publicly that there will be no XHTML 1.2. Nor will there be an HTML 5 or even an HTML 4.1. The future will be filled with web features that require XHTML 2. (The first of those, XForms, will be the subject of a future article.)

All of which brings us, in a roundabout sort of way, to today's topic:

The <object> Element

Although it's been around for years, the <object> element is unappreciated and rarely used. It was meant to be an replacement for several other elements: <img>, <applet>, and the non-standard <embed>. <object> features multilevel fallbacks; you are supposed to be able to define multiple choices for a single object (for example, the same image in multiple formats), and browsers are supposed to render the first one they can. If none of the choices work out, you can fall back on text; not just plain text (like the alt attribute of an <img>), but full HTML markup.

This will be clearer with an example. Here is an image, which you could embed in a page with a single <img> element:

<img id="beagle"

  src="beagle.jpg"

  alt="Beagle in a woman's lap"

  width="152"

  height="160" />

You could embed the same image using the <object> element, like this:

<object id="beagle"

  type="image/jpeg"

  data="beagle.jpg"

  width="152"

  height="160">

<p><span class="breed">Beagle</span> in a woman's lap</p>

</object>

Several things to note here:

  1. The <img> element does not specify a MIME type; that is handled by the web server. The <object> element explicitly states the MIME type of the linked image file.
  2. The alt attribute of the <img> element is limited to plain text. The <object> element achieves the same purpose (a graphic with text fallback), but it can support full HTML markup for the text fallback.
  3. The <object> version won't actually work.

Why won't it work? Well, it will work in some browsers. But not in Internet Explorer. The <object> element is a good idea; unfortunately, it came a bit too late in the game. Before <object> was officially added to the HTML specification in 1997, Microsoft had already introduced its own vendor-specific element in Internet Explorer 3.0 as a way of embedding ActiveX controls in web pages: an element named... <object>.

When <object> was later standardized, Microsoft retrofitted support for it, sort of. Except that, to this day, even the latest version of Internet Explorer treats all <object> elements as ActiveX controls. Which means that if you have your security settings on "high" (disabling all ActiveX controls), you won't see any <object> elements, even ones that have nothing to do with ActiveX (like the above example).

Even if ActiveX in enabled (which it is by default), Internet Explorer renders the above image with a nasty border, and two sets of scroll bars. (demo)

Oh, and remember when I said that you were supposed to be able to nest <object> elements and let the browser choose between multiple formats of the same image? Well, that doesn't work in Internet Explorer either; instead of rendering the first one it understands, it renders all of them.

And this is why you've never heard of the <object> element.

But no big deal, right? I mean, who cares about <object> since we'll always have <img>?

Bye, Bye img

XHTML 2 doesn't have an <img> element. It doesn't have an <applet> element either. Both have been obsoleted by -- wait for it... -- <object>!

So is there a way to ease the migration to XHTML 2? Is there a way to start using <object> now instead of <img>?

A Partial Solution

Let's be clear: the problem is Internet Explorer. Mozilla (and Mozilla derivatives like Netscape )7 renders <object> just fine. So does Opera. (Here's that demo again of the picture of the beagle. Here are some more tests to check your browser's support for <object>.) Internet Explorer has four problems:

  1. Renders all nested <object> elements.
  2. Renders visible border by default.
  3. Renders visible scrollbars by default.
  4. Doesn't render if ActiveX is disabled.

The first problem can be worked around by simply not nesting <object> elements. ("Doctor, it hurts when I do this...") But that's a cop out. What if you really want to use fallbacks for different image formats? Then you can use what are called conditional comments, a Microsoft-specific technology that doesn't conflict with any standards and doesn't cause any compatibility problems in other browsers. ( more on MSDN)

Let's say you had two versions of the beagle picture, a JPG and a TIFF. It looks like this:

<object

  type="image/tiff"

  data="beagle.tiff"

  width="152"

  height="160">

    <object

      type="image/jpeg"

      data="beagle.jpg"

      width="152"

      height="160">

    </object>

</object>

But in Internet Explorer, this will render both the TIFF and the JPG (that's wrong!), unless we use conditional comments:

<object

  type="image/tiff"

  data="beagle.tiff"

  width="152"

  height="160">

<!--[if !IE]>

    <object

      type="image/jpeg"

      data="beagle.jpg"

      width="152"

      height="160">

    </object>

<![endif]-->

</object>

The second problem, the visible border, can be solved with a clever bit of Javascript. (All of the following Javascript solutions were donated by a semi-anonymous reader named "John" when I posed this question on my own personal site several months ago. Thanks, John.)

The trick to tackling the <object> element is to realize that it acts like an <iframe>; that is, it is its own canvas within a canvas. Within the DOM, an <object> has its own body with all its own properties. So to remove the border, we simply do this in our window.onload function (demo):

beagle.body.style.border = 'none';

(beagle is the value of the id attribute we defined in our <object> element.)

The third problem, the visible scrollbars, can be solved in a similar fashion (demo):

beagle.body.style.margin = '0';

beagle.body.style.padding = '0';

beagle.body.style.overflow = 'hidden';

You're likely to have more than one <object> per page. Even if you're not in a dynamic application environment, you'll want to abstract this Javascript code into a single function that you can just link from each page, without worrying about the specific objects or IDs on each page. You can do that with the getElementsByTagName function (demo):

<script type="text/javascript">

function fixObjectImages ()

{

  var objs = document.getElementsByTagName ('OBJECT');

  for (n = 0; n < objs.length; n++)

  {

    var obj = objs [n];

    if ((obj != null && obj.type != null)

      && ((obj.type == "image/jpeg") || (obj.type == "image/gif")))

    {

      fixObject (obj);

    }

  }

}



function fixObject (obj)

{

  obj.body.style.border = 'none';

  obj.body.style.margin = '0';

  obj.body.style.padding = '0';

  obj.body.style.overflow = 'hidden';

}



window.onload = fixObjectImages;

Unfortunately, the fourth problem can't be worked around. Internet Explorer incorrectly treats all <object> elements as ActiveX controls and, therefore, won't render them if ActiveX is disabled. Depending on the user's security settings, the image may simply not appear; worse, they may be prompted with a "Would you like to allow programs such as ActiveX controls to Run?" dialog, which is likely to scare off even the most dedicated readers.

Postscript

Remember when I said that Internet Explorer was the only browser with <object> issues? I lied. There are other issues, of varying degrees of importance.

More Dive Into XML Columns

Identifying Atom

XML on the Web Has Failed

The Atom Link Model

Normalizing Syndicated Feed Content

Atom Authentication

  1. Mozilla 1.3 doesn't handle the <object> image the same way as an <img> image. Right-clicking on it will not show you the usual image properties, or "block images from this server", or any other image-specific functions. I believe this will be fixed in Mozilla 1.4. Opera 7 has a similar problem.
  2. Opera 7 treats <object> like inline frames (the <iframe> element). This means that if the user has intentionally disabled <iframe> support (say, to block ads, a common use of iframes), they won't see your <object> either.
  3. Several browsers, including Opera 7 and the latest final candidate release of Mozilla 1.4, will not display the fallback text within an <object> if images are disabled.
  4. On the flip side, if the user has disabled images in Internet Explorer, it will still render your image-in-an-object.
  5. Screen readers for the blind, such as JAWS, will read the text of an image's alt attribute aloud. However, they do not support reading the fallback text within an <object> element, thus rendering your objects completely inaccessible.
  6. I've also seen unconfirmed reports that Internet Explorer doesn't let you position anything over an <object>. For example, on an interactive site, you could create a draggable <div> on top of an <img> element, but that doesn't work with <object>.

Bottom line: using <object> as a replacement for <img> is not a safe bet right now. It's possible that by the time XHTML 2 is finalized, and we have working implementations in next-generation browsers, the current generation of browsers will have fixed these quirks. But from here the migration path to XHTML 2 looks a little bumpy.