Firefox DOM - whitespace and newline

August 3rd, 2005
previous     next

In general I think Firefox’s handling of the Document Object Model (DOM) is excellent. The simple fact that they have DOM inspector puts them leagues ahead of anyone else.

But I recently came across something that I find surprising - not to mention pretty annoying.

Say I write the following XHTML:<div id="parent">
  <div id="childOne"></div>
  <div id="childTwo"></div>
</div>

If I have a look at this code in the DOM inspector, I see the following:
node map
Looks good.

So now lets say I write a small bit of javascript. What I want to do is get the first <div>, childOne, then get it’s sibling. I might do this:child1 = document.getElementById("childOne");
nextChild = child1.nextSibling;
window.alert(nextChild.id);

Making use of nextSibling, I would expect this script to give an alert box with the text childTwo. In fact, in IE it does just that.

But in Firefox, you get undefined. Why?

Well I ran into this problem in a much more complicated application, so it took a long while to track down. But the answer is simple (and annoying).

Back to the DOM inspector. If I highlight the childOne <div>, then look at it’s javascript properties, I’ll see this:
Javascript DOM info fail

There’s the problem. According to the Firefox DOM, this <div>s next sibling is “#text”. I would expect it to be the second <div>. So what’s going on?

Notice in my original XHTML I put the two child <div>s on separate lines. So there’s a linebreak in there. Turns out that Firefox is picking up that linebreak and treating it as a text node in the DOM. Unfortunately it doesn’t show up in the DOM inspector’s node map, but only in the Javascript properties.

So if I get rid of the line break like so:<div id="parent">
  <div id="childOne"></div><div id="childTwo"></div>
</div>

Then go back to the DOM inspector I get this:
Javascript DOM info success

Now I’m getting the <div>s next sibling is “DIV”. That’s what I would expect. Notice in both of those images of the DOM inspector, the left pane is identical. There’s no indication that in the first instance there is actually a text node hidden between the <div>s.

So it appears that the Firefox DOM does not ignore line breaks. In fact, I tinkered around and it does not ignore whitespace at all. I find this surprising.

The W3C spec is a little non-committal on the subject. It says “This specification does not indicate the behavior, rendering or otherwise, of space characters other than those explicitly identified here as white space characters.” But in general browsers ignore whitespace. They give any amount of whitespace a single space when rendering. Thus the necessity for the <br /> tag and &nbsp;. This makes good sense. So it’s surprising to see Firefox give weight to whitespace and linebreaks.

So that’s the deal with that. But there’s still the practical problem of wanting to use nextSibling and not being able to. Again, IE works fine, so I needed a way to get Firefox up to speed. For my purposes, I chose to do the following:

  1. get the next sibling
  2. if this sibling is “#text” (or anything else other than an element), get the next sibling (so, the sibling’s sibling).
  3. repeat this until I hit a valid element

So I wrote the following javascript function:function getNextSibling(startBrother){
  endBrother=startBrother.nextSibling;
  while(endBrother.nodeType!=1){
    endBrother = endBrother.nextSibling;
  }
  return endBrother;
}

So for the example I started with, instead of writingnextChild = child1.nextSibling;

I would now write nextChild=getNextSibling(child1);

This works in both IE and Firefox. A quick walk through that function: I’m basically getting the element’s nextSibling, then checking it’s node type. A node type of 1 indicates an element, which is what we care about. If the sibling we found isn’t of type 1, we get the next sibling, and check again. Repeat until we hit what we’re looking for. There are some potential problems here. First, if we never hit a valid element, this will go until it runs out of siblings, then will throw an error. Second, if the nextSibling is text, is going to the next sibling the right thing to do? It might not be.

I wrote a similar function for the firstChild function which I was also using.

The bottom line is that the Firefox DOM’s treatment of whitespace is really pretty annoying. I can’t say it goes against the spec per se, but I think a little more thought needs to go into this.

Comments? Let's hear 'em:

  • #1 : Em

    Excellent! Thank you, thank you thank you!

    I have had this same problem, but couldn’t sort out the source of the problem.

    This was it!

  • #2 : Patrick Ryan

    Well thanks to the folks at the web standards group, I’ve had some clarification on this.

    By design, firefox considers whitespace to be DOM nodes. Mozilla has a document here

    The idea is that the same DOM should apply to XML and XHTML. That is the whole idea behind XHTML right?

    I gotta say though - whitespace is ignored by browsers in display (in fact you can’t make it relevant if you want to) so should it be relevant in the DOM?

  • #3 : Mike

    I think having the whitespace is fine, and may be particularly useful in some unique cases. However, I think it should be *optional* in the parser (and turned off by default). I imagine that 99.9999% of the time, people use spaces, tabs and/or carriage-returns to make XML human-readable…while similarly 99.9999% of the time, nobody cares about them while parsing the XML in code.

  • #4 : Patrick Ryan

    Mike,

    I’m with you on this in practice 100%.

    In theory though, I’ve considered it further, and my comment above, “browsers ignore whitespace” is not accurate.

    The PRE tag respects whitespace. In fact all tags are aware of whitespace, but every tag except PRE just styles it away.

    So whitespace is not ignored by browsers, nor by the DOM.

    But again, in practice… it’s a different story.

  • #5 : Timmo

    Hi guys,
    I totally agree. If they really want to use the DOM parser for xml as well as for xhtml, it doesn’t make sense to incorparate breaklines. Since xml will almost always be formatted using breaklines and tabs to have some readability of the xml.
    However the responsibility for this issue might lie with W3C first. If they would specify that whitespaces and breaklines should be standardly ignored and optionally turned on. I’m sure that the mozilla firefox team would incorparate this. As well as other W3C following developments (which should be all).

    Cheers!
    …Timmo

  • #6 : Maroun

    Thanks,
    you saved my code, I didn’t understand why the nextsibling return Text Object and that works in IE.
    Good Job

    Merci

  • #7 : Larry

    Also, white space is significant in text areas and text inputs.

  • #8 : Phil

    Many thanks for the explanation! Hit the same problem myself, and kind of worked round it by trial and error. I always worry about using hacks, though, when I don’t know WHY they work. Now I can sleep easy…

  • #9 : Mike

    Bingo! I hit exactly the same issue and your code came to my rescue. I can now put to bed a longstanding problem report.

    Thanks.

  • #10 : jonathan

    Found your post from way back last year… but still relevant! Thanks.

    How about checking endBrother before accessing it’s nodeType, to avoid JavaScript errors when running out of siblings:

    while(endBrother && endBrother.nodeType!=1){ …

  • #11 : Nate

    Yeah, I’m working on what I though would be a simple AJAX problem: pulling, essentially, a text file from the server, treating it as xml, and parsing it, but the resulting javascript DOM object seriously tripped me up for the last two days…. I don’t like it at all.

  • #12 : Matt Turner

    Nice function, this problem is annoying.

    What’s really strange is that IE often renders stuff to the display to do with whitespace, but then ignores it in JavaScript. Mozilla usually ignores it when rendering but ’sees’ it when traversing the DOM in JavaScript. Argh!

  • #13 : Kilian

    Brillian!

  • #14 : Seph Lietz

    Thanks for the solution. Luckily I stumbled across this after only a few minutes of debugging. Works perfectly.

  • #15 : Matt

    Thanks for the info. I’m just starting to learn how to manipulate DOM with Javascript, and I was wondering why, when I made a “while” loop to list the childNodes of my div, it kept showing these random “text” elements there. I’m amazed to see Firefox being a problem as opposed to IE for once.

  • #16 : Chris

    Thanks, saved me trouble!

  • #17 : Amit

    This was great help. Thanks.
    Had the problem in a web app i’m developing, tried to get to the root cause of it for a couple of days to no avail, 15 minutes after I found this post - problem solved.

  • #18 : Raffy

    Hi,I found your post very useful.

    I have only modified your while condition from:

    while(endBrother.nodeType!=1){

    to

    while(endBrother && (endBrother.nodeType!=startBrother.nodeType)){

    in order to avoid errors if you reach the end of the document.

    Thank you very much :)

    Bye
    Raffy

  • #19 : Look! A BLOG! » Fun With White-Space

    [...] Apparently W3C’s spec leaves it up to the UA to figure out what to do with whitespace, and Firefox is treating white-space as a text node in the DOM model (no, I didn’t figure out that part: this one guy looked at the DOM inspector for some javascript he was coding). Which confirms my theory that Firefox is turning my linebreaks into a space. I suppose there’re some technical reasons Firefox does this, but it’s really, really annoying. [...]

  • #20 : JavaScript nextSibling Firefox bug fix at Andrew Sellick

    [...] The full article can be found on the Agave Group Design website. Filed under: Uncategorized   |   [...]

  • #21 : Maz

    Actually, the implementation is correct, XML parsers must be aware of whitespace. If you have used XML parsers in other languages you have to specify if you want to ignore whitespace nodes. I’m doing some research to find if there is an option to ignore whitespace nodes in mozilla. Else I will have to code something to remove the whitespace nodes before processing my xml.

  • #22 : PS

    (belated comment) Thanks for the workaround. What a weird decision to implement the previousSibling, nextSibling. Thanks to Mozilla for making life more complicated than it really has to be.

  • #23 : Marcus Nyberg » Arkiv » firstChild and nextSibling differences between Firefox and Explorer

    [...] This post describes a weird difference in how Internet Explorer and Firefox handles the Document Object Model (DOM). In my case I got different browser-behaviour when using firstChild and nextSibling in a javascript. The problem is that the Firefox DOM does not ignore line breaks and whitespaces while IE does. [...]

  • #24 : Svelon

    IE and Firefox different approaches on several things are really torturous.
    This article just saved my day, so thanks :)

  • #25 : Johanna

    Hey:)

    Thanks!!!!!!

    nextSibling function worked great for me. Just wondering about the firstChild version of the function, can you post it - i’m a bit confused:-(

  • #26 : David Meade

    Thanks for this. I was having the same problem. I needed the solution for firstChild, but managed to figure it out thanks to the function you provided above.

  • #27 : 5h4rk

    Wow, this works, thanks you!

Leave a Reply

name (required)

email (will not be published) (required)

website

comment