On non-breaking inline elements that overflow horizontally and cause anger and strife
Published by Jon October 23rd, 2006 in TechnologyLately, I’ve been working hard on revising the interface for managing and exploring workspaces. One of the challenges that popped up in the process was creating a list of contacts known to the user to making inviting them easier. Del.icio.us does this with tags; when you go to bookmark a new page, it presents you with a list of tags you’ve already used to make it easier to work with them.

You’d think that the “hard” part (not that any of it should really be pushing the state of the art) would be actually keeping track of who the user has interacted with and transmitting that information in some sane way. Displaying it should be trivial. Should.
I knew what I wanted the list to look like on the page; again, very much like del.icio.us does. I would implement it as an unordered list with inline-display list elements. The list should wrap when it hit the edge of its container, flowing gracefully into a downward-expanding paragraph-like doohickey if the list got too long.
Again, notice the presence of “should.”
I had the list of contacts represented as an array in JavaScript, so I figured it would be easy enough to append each item to the list in turn as a dynamically generated DOM object. I wrote the function to generate the list, loaded the page, triggered the function, and watched with disappointment as it generated a list that extended much too far to the right.

What could be wrong? Although it’s not clear from this screenshot, the list is buried pretty deep inside the DOM. I fiddled with styles for a bit hoping for a quick/obvious fix, but finally concluded that something more complicated than a simple CSS error or typo was at play and decided to construct a minimal test case.
For the first part of the test, I created a container div, an unordered list, and fifteen list items. I set the styles to closely emulate what was going on in the real situation; the container and list both had fixed widths, and the list items were set to display inline. To my surprise, it worked. The list wrapped as soon as it hit the edge of its container.

For reference, here’s the [slightly trimmed] HTML I used:
As for the stylesheet:
Strange indeed. I fiddled with the HTML/CSS for a while, trying all kinds of strange things to make the non-breaking error reappear. No luck. I simply couldn’t reproduce the problem.
My next thought was that I’d somehow discovered a browser bug that existed in every browser at my disposal (Firefox, IE, Opera, Safari, and Camino). That seemed extremely unlikely, but it might be that it’s some strange standards-compliance rule that’s just really obscure. Maybe. I thought a bit about what could trigger one of those.
Since the list was being generated dynamically, maybe there was some strange interaction between the order of creating the DOM objects, applying styles, and actually appending them to the DOM. To test the idea, I decided to do a minimal test-case in JavaScript.
The first step was to generate the exact same list I had built in HTML. The code for that:
(note: although I’m using “dynamic-container” as the id, the styles are identical; this was just so I could change styles for the hard-coded and dynamically generated lists independently later).
To make sure that everything was parsing and running correctly before I started fiddling with execution order, I reloaded the page to make sure the dynamically generated list was identical to the hard-coded list. I was surprised to see that they were quite different. The dynamically generated list failed to wrap, while the hard-coded list wrapped just fine.

How could that be? The lists are, DOMologically, identical… aren’t they? To make sure, I inspected the DOM using Firebug. Firebug clearly showed that the DOM representations of the two lists were identical, as were all styles.
I started fiddling furiously with the execution order of the script, rigorously trying every valid combination of steps. All produced the same result: the list wouldn’t wrap.
For those of you who are keeping score, we’ve ruled out any difference in CSS from the rendering engine’s perspective. There’s no difference in the DOM representation of either list. No permutation of script execution order will make things better. Although I won’t go into the details, no amount of adjusting the elements around or above (hierarchically) the list in the DOM will make it work. So what gives? Is there anything left to change?
It turns out that there is. I don’t know how or why I thought of it, but I did. I changed the script so it reads as follows:
See the difference? Now we’re throwing in whitespace after each list item element. I reloaded the page and, sure enough, the dynamically-generated list was now wrapping just fine in all browsers.
Here’s what’s going on: the original, hard-coded HTML list had newlines and tabs between each tag. Although the lists were right next to each other in the DOM (as Firebug reported), they had newlines and tabs between them. Really, the HTML list looked more like this (I’ve replaced the angle brackets with square brackets to prevent Wordpress from reformatting them):
[li]…[/li]\n\t\t[li]…[/li]
The dynamically-generated list, though, had no such whitespace. Instead, it looked like this (again, brackets replaced):
[li]…[/li][li]…[/li]
By adding spaces between each list element, we give the browser something to actually break on. Otherwise, what we’re doing is analogous to typing a paragraph with no spaces. The browser, in that case, would treat the whole thing as a single word and would not wrap properly at the edge of a container.
Whew.
So can this problem be generalized a bit more? It turns out that it can. This will happen whenever you place a bunch of elements with the ‘display’ style set to ‘inline’ inside of a container. If there’s no whitespace between the inline elements, the browser won’t wrap them to a new line of the container. That goes for spans inside of divs, inline list items inside of lists, and so on.
To solve the problem, add whitespace somewhere. Anywhere. Adding it between elements or even within elements will work just fine. If the list items had contained spaces (e.g. “list item” instead of just “item”), the problem never would have come up in the first place.
I doubt that this one comes up too often, but I hope this is helpful to at least a few people.
I shall keep it in mind. Thanks for the writeup! By the way, an interesting (although invalid) tag is (or Word BReak) which functions as a zero-width space that wraps, to prevent any whitespace from rendering. Here’s a writeup (http://www.quirksmode.org/oddsandends/wbr.html)
Works in IE and Gecko, but sadly not Safari, my browser-of-choice.
Good find — thanks!
great work! you made my day as I had the same problem with an inline-menu that was generated by a CMS. with the help of your find, I solved it in no time. thanks for the effort that you put in figuring this one out.
Rainer, I’m really happy to hear that this was helpful to you. Good luck with your project!