Same DOM Errors, Different Browser Interpretations

Introduction

In this article I will explore the DOM, look at some common kinds of errors that are found in the DOM and how different debugging tools can be used to find such DOM errors and make sure that the DOM is interpreted consistently across browsers. Along the way, I’ll introduce Opera Dragonfly, the new kid on the web development debugging block, and show how it performs.

What is the DOM?

When a browser receives HTML code from a website, it creates a structured overview of the HTML document. This overview is known as the DOM, and through its structure JavaScript can access the various parts of the document.

The “parent” of the DOM is the document object, and using its methods and properties you can reach every part of the HTML file — for example by getting the first div with document.getElementsByTagName('div')[0] or the first element in the document with document.firstChild.

The DOM is usually visualised as a tree-like structure, as seen in Figure 1. The document itself should have only one child — typically the html element — and that element usually has the two children head and body. Each of those can have several children, so comparing this structure to the branches of a tree is a good way to understand it.

The DOM structure of a simple HTML document as a tree

Figure 1: The DOM structure of a simple HTML document, as viewed in the DOM viewer of Opera Dragonfly as a tree structure.

When constructing the DOM, the quality of the markup is very important. If the markup is not valid — for example if elements are not closed correctly — it’s much harder to create a tree structure from it. If, say, a document contains the markup <html><head><body></body></html> — what is the browser going to do? Make body a child of head? Since the head contents are not visible in user agents, this might make the entire document disappear!

Because invalid markup is so common, browsers have to add lots of special rules for creating DOM structures from invalid markup. These rules differ somewhat between browsers, which means that using invalid markup dramatically increases the risk that your site will appear differently in different browsers — or even break completely in some of them.

Common markup / DOM errors

Below I will look at some commonly encountered DOM errors, and how browsers interpret the markup.

Bad closing and nesting of elements

If you look at the first example file — df-dom-demo-unclosed-b.htm — you will see that the markup is invalid — there are multiple problems with it, in terms of unclosed elements and incorrect nesting. If you look at the generated DOM in various web page debugger tools (see Figure 2), you will see that browsers interpret this HTML very differently.

example invalid dom interpreted by Opera Dragonfly
example invalid dom interpreted by firebug
example invalid dom interpreted by IE developer toolbar

Figure 2: From top to bottom, this shows our incorrectly closed/nested example DOM as represented in Opera Dragonfly, Mozilla Firebug, and the Internet Explorer developer toolbar.

The DOM inspectors reveal that these browsers handle markup errors in very different ways: Opera makes the subsequent elements children of the b that lacks a closing tag. Firefox adds extra b elements between the p tags that were not present in the markup. In IE’s DOM we see that the text “This text should be a link” in fact appears to be outside the a tag that creates the link.

Because there is no standard way to handle invalid markup, none of these browsers are doing anything particularly wrong here. However, if you start adding extra styling like display:none to any of these elements or try cloning and manipulating them through the DOM, you’ get unexpected results across browsers because of the way the invalid markup is parsed into different DOM structures.

body inside the head

In the second sample file — df-dom-demo-head-contents.htm — you can see another example of invalid markup. There is a div element inside the head section. Check out this demo in various DOM explorers and you will see that all browsers move the div element out of the head and into the body. Figure 3 shows the different ways in which this DOM is interpreted by different browsers:

example invalid dom interpreted by Opera Dragonfly
example invalid dom interpreted by firebug
example invalid dom interpreted by IE developer toolbar

Figure 3: From top to bottom, this shows our content in the head example’s DOM as represented in Opera Dragonfly, Mozilla Firebug, and the Internet Explorer developer toolbar.

In Opera and IE, this means that any head content after the div also is moved outside of the head section. Also note the way Firefox has moved the style element from the body into the head. style elements are not allowed inside the body of course, so this is a logical thing to do, but it might confuse your script if it goes looking for the style element in a certain place in the tree.

Using DOM inspectors for debugging

As you have seen above, using DOM inspectors is a great way to see how browsers interpret the markup. This view can help explain issues you may run into when using the DOM via a JavaScript application. Some of the following examples are rather advanced, and it helps to have several of the DOM inspectors mentioned installed so that you can test the demos by yourself. The DOM inspectors used for the below analysis are Opera Dragonfly, Mozilla Firebug, the Webkit (Safari) Web Inspector, and the IE Web Developer Toolbar.

The third example file — df-dom-demo-app-meta.htm — is created by a rather unlucky web developer who has made several assumptions about how the DOM works. It turns out that he is wrong on most counts, and the app causes issues in most browsers! To start with, it doesn’t include a proper doctype in the first line. It then goes on to include a custom test element and a meta element with a custom http-equiv attribute value inside the head. Lastly, it includes a script inside the body that tries to read attribute values from both the meta and the test elements.

  • In Opera it generates two exceptions. Using the Opera Dragonfly DOM explorer (see Figure 4) you can see that the reason is that the test and meta elements are not inside the head. When Opera sees the test element, it thinks the custom element name indicates the page content start, so it closes the head section and traps both elements outside it.

    the debugging example in dragonfly

    Figure 4: Opera Dragonfly shows that Opera has trapped the two rogue elements outside the head. Hence, when the script looks for them inside the head section it can’t find them and throws exceptions.

  • In Firefox (see Figure 5), you will get the odd output message “name of bar attribute is _moz-userdefined” and sure enough, with Firebug’s DOM explorer you will see that Firefox added a _moz-userdefined attribute to the test element.

    the debugging example in firebug

    Figure 5: Firebug shows that Firefox has returned an error message and added an attribute to mark the test element as undefined in HTML. Since the script reads the first attribute from the element, it sees the _moz-userdefined attribute instead of what we expected.

  • In WebKit you get one exception (see Figure 6). Like Opera, it moves the test element out of head. Unlike Opera, it appends the element to body, and it doesn’t move the meta element.

    the debugging example in webkit

    Figure 6: WebKit shows that Safari has moved the test element into the body.

  • In IE7 the output is “Name of bar attribute is language. Value of meta attribute is null” — there are no exceptions reported, and neither result is what was expected. The IE Developer Toolbar’s DOM view is not quite powerful enough to explain these results — there are two IE bugs at play here: one is that IE exposes internal generic attributes in the Element.attributes collection, second is that weirdly enough the meta http-equiv attribute simply disappears. See Figure 7 for the output in the IE web developer toolbar.

    the debugging example in the IE web developer toolbar

    Figure 7: The IE web developer toolbar does not quite show us the DOM the scripts are working on. It appears to show that IE has preserved the meta http-equiv attribute, yet when we try reading it with the DOM method getAttribute() we get nothing.

Summary

Our unlucky developer has a few things to fix to get this example working properly cross-browser, but in this example it’s not hard to do so. He’ll need to validate the markup, get rid of the custom elements (and avoid these in the future, particularly inside the head as browsers are very picky about what they allow to appear there), and not rely on attribute order when reading attributes. You can see from the examples shown above that valid code is perhaps the most important factor for cross-browser compatibility on the DOM level, and that DOM inspectors help you understand how your scripts can access the document and how the markup is interpreted.

Free Workshops

Watch one of our expert, full-length teaching videos. Choose from either HTML, CSS or Wordpress.

Start learning

Comments

2 comments on “Same DOM Errors, Different Browser Interpretations

  1. Pingback: Programación en Internet » ¿Por qué escribir HTML válido es importante?