Embedding Content like it's 2009

last modified 2004-07-24 by jon

Introduction

With XHTML 2.0 comes a new approach to embedding content. The proposed method is flexible, semantically sound, and degrades gracefully in every browser. Rather than introduce a new tag, XHTML 2.0 adds new attributes to existing tags as a means of embedding objects. These new attributes are src and type. If these attributes are present and the browser supports the specified mime type, it should render the object in the place of that element and its contents. If the type is not supported, or if the browser doesn't understand these attributes (as is the case with existing browsers), it will simply render the element and its contents.

An example

What does this mean? Well, for starters, we don't need the <img> or <iframe> tags anymore. Let's look at a simple image replacement example to see how it works:

<h1 src="title.png" type="image/png">Document Title</h1>

Image-capable XHTML 2.0 browsers will render "title.png" in place of the heading. All other browsers will simply display the heading and its text. Search engines will correctly index the text as a document heading. And it's much simpler and more intuitive than existing methods. This technique could also be used to embed audio, video, applets and more, while at the same time providing one or more fallbacks for browsers that don't support the specified object.

The future is today. Sort of

It will be many years before this behavior is actually supported by the majority if browsers, as XHTML 2.0 is still a working draft. But don't let that stop you from trying it out! Below is a simple script you can include in your documents that will emulate the XHTML 2.0 Embedding Attributes module. It has been tested on IE Win 5-6, Opera 7.5 and Mozilla 1.6, and will probably work on earlier versions. It has not been tested on Safari, but it should work. You're probably out of luck with Netscape 4 and IE Mac.

window.onload = srcFix;
function srcFix(){
  if(window.opera)//opera needs its own function, since it has issues w/ getAttribute()
    fixNodeOpera(document.body);
  else
    fixNode(document.body);
}
function fixNode(node){
  var ret = false;
  //if the node has src and type, let's fix it
  if(node.tagName && node.getAttribute('src') && node.getAttribute('type')){ 
    var newNode;
    //is it an image?
    if(node.getAttribute('type').substring(0,6) == "image/"){
      newNode = document.createElement("IMG");
      newNode.src = node.getAttribute('src');
      newNode.alt = newNode.innerHTML.replace(/^\s*(.*[^\s])\s*/,"$1").replace(/<[^>]+>/g,"");
    }
    else{
      newNode = document.createElement("OBJECT");
      newNode.type = node.getAttribute('type');
      newNode.data = node.getAttribute('src');
      newNode.innerHTML = node.innerHTML;
    }
    node.parentNode.insertBefore(newNode,node);
    ret = true;
  }
  //now we fix all its child nodes
  node = node.firstChild;
  var remove;
  while(node != null){
    rem = fixNode(node);
    nextNode = node.nextSibling;
    if(rem)
      node.parentNode.removeChild(node);
    node = nextNode;
  }
  return ret;
}

function fixNodeOpera(node){
  var ret = false;
  if(node.tagName){
    //if the node has src, let's fix it (we can't get the type in Opera. d'oh)
    src = node.outerHTML.replace(/^<[^>]+SRC="/,'');
    if(src != node.outerHTML){
      var newNode;
      newNode = document.createElement("OBJECT");
      newNode.data = src.substring(0,src.indexOf('"'));
      newNode.innerHTML = node.innerHTML;
      node.parentNode.insertBefore(newNode,node);
      ret = true;
    }
  }
  //now we fix all its child nodes
  node = node.firstChild;
  var remove;
  while(node != null){
    rem = fixNodeOpera(node);
    nextNode = node.nextSibling;
    if(rem)
      node.parentNode.removeChild(node);
    node = nextNode;
  }
  return ret;
}

To try it out, save the source, add <script type="text/javascript" src="embed.js"></script> to your document head, and start embedding like it's 2009. It should work on pretty much any tag that has type and src attributes.

While it correctly emulates the embedding behavior, there are some obvious drawbacks. It does not validate, it only works on browsers with scripting turned on, it's relatively slow on large documents, and it only adds the embedded elements once the page has finished loading. And when you consider that XHTML 2.0 is still incomplete and could yet change, it becomes obvious that this isn't suitable for production use. But it's kinda fun nonetheless.

Questions? Corrections? Suggestions? Email me. Feel free to use these scripts throughout your site with or without modification or acknowledgement, although a link to me is always appreciated. Email me if you would like permission to reproduce this article.

Compatibility

Related Pages