CSS inline/block nuances
As pointed out by Nicolas Gallagher on Twitter; I made a mistake in the original article - inline and inline-block both behave in the same way, yet I had never noticed that inline also has odd behaviour involving whitespace in the code.
When you set an element to display:inline-block;
or display:inline;
browsers treat HTML whitespace adjacent to the styled element as though it were content.
At first this confused me, and I assumed the implementation in Safari and Firefox was buggy. The weird gaps either side of elements set to display:inline-block;
have annoyed me for a while And I’d not noticed the same effect on display:inline;
before. Normally whitespace outside of an HTML element has no effect on how it’s displayed, and even inside an element (except <pre>) whitespace collapses to a single character even if there are multiple characters in the code. Except here. The following code blocks produce differing results.
<ul>
<li>one</li>
<li>two</li>
<li>three</li>
</ul>
<ul><li>one</li><li>two</li><li>three</li></ul>
When we set the list item to display:block
both code examples render a list where each item appears one under the other. When we use display:inline
or display:inline-block
, there is a display difference between the code examples. They are both laid out horizontally, but the first example has whitespace between each item: it reads “one two three”, the second has no whitespace and reads “onetwothree”.
That’s odd behaviour for HTML, but it sort-of makes sense in context of the definition for the property. It’s aiming to make the styled element behave as though it was inline, whilst rendering as though it’s a block. It’s trying to make a “block” part of a sentence. It treats the block as though it was a word, and puts spaces either side if there are spaces either side of the element in the code.
Frankly, I hate this behaviour. It means if I format my code so it’s readable I end up with spaces either side of an element. That’s dumb. If I want a space either side I can set a margin on that element. However with the behaviour it has now, I can not remove the spaces using CSS without refactoring the whitespace around the HTML element in the source code. This was driving me insane at work.
Entry Information
- Posted:
- Tue, 12th Jan 2010 at 21:01 UTC
- Filed under:
- Tags:
Comments
skip to comment formFirstly, I'm unsure what this post has to do with CSS3 (noted in the post title) specifically, since 'inline-block' was first defined in CSS2.
"Normally whitespace outside of an HTML element has no effect on how it’s displayed…"
What you're seeing here are whitespace nodes that form a sibling relationship with adjacent element nodes. Whilst this whitespace doesn't affect how an individual inline box is laid out (since there are no adjacent inline boxes that would highlight it's presence), it will create space between multiple inline boxes, as you're seeing here.
"That’s odd behaviour for HTML, but it sort-of makes sense in context of the definition for the property"
There are no differences here between a box that is formatted as inline and one that is formatted as an inline-box - both values cause an element to flow as a single inline box. More so, I'd suggest that in the vast majority of cases where authors create inline-level elements (separated by line feeds, etc) in the source, it's advantageous to collapse those line feeds into single-space characters - as opposed to having no spaces at all.
As I see it, 'inline-block' is simply an extension to the inline box model, since it has the added benefit of being able to take property/value pairs that affect only block boxes. Whilst on the surface may seem a plausible candidate as a replacement to the float model (in the context of your post), it's still flowed as an inline box which results in unwanted whitespace between adjacent inline elements, as we're seeing here.
You could of course remove the whitespace text nodes directly from the DOM, but this is far from adequate at least from a presentational point of view. In fact there is a white-space-collapse property in css3-text [1] that has the ability to suppress whitespace in the way you desire, although it hasn't been implemented by any vendor as of yet.
[1] http://www.w3.org/TR/css3-text/#white-space-collapse
CSS3 was a typo, corrected now thank you.
My point is that it is very weird for the formatting on the HTML source to have any effect on the way that is then rendered. HTML is not supposed to be whitespace sensitive outside of a tag. To my mind there shouldn't BE any whitespace text node in the above example because that whitespace is outside the tag, not inside it. Which should have no effect.
It is very logical for inline elements to be sensitive to their surrounding whitespace.
Lets say I have to highlight *this* *and this* word.
If you surround both text nodes with inline elements (lets say, strong and em) the space between the words remains. This is a good thing. You wouldn't want to end up with *thisand this* cobbled together because the whitespace was collapsed.
It's also very annoying in *some* cases, like the one you highlight.
That's why implementation of white-space-collapse would be extremely useful. When implemented inline-block elements can be used to their full extend, no more need for floats to get things to line up the way you want.
Somehow I can't find a bug in Mozilla's Bugzilla to track the implementation, I guess nobody is working on it and it's not even on the radar?
Good point Jaap, and one I had not considered with my head stuck in "layout" mode. Thanks for illustrating the rational for the behaviour.
It seems like the whitespace property isn't getting much attention, it's one of those things that's extremely useful in a very few use cases, so I'm not surprised. It's like widow control and how it has never been updated to work with screen media instead of just print. Extremely useful if you care about good typography, but just not worth bothering with if you're a browser vendor it seems.
To explain in further detail.
#text ("foo")
#text (n)
SPAN
#text (n)
#test ("bar")
As per the CSS 'white-space' processing model [1], ignorable white space will be collapsed, so the rendering reads in the format of 'foo SPAN bar'. This default model encourages authors to write legible markup (often emulating the hierarchy seen in the document tree (i.e 'pretty-printing')) by including newlines, tabs and spaces in the source, whilst sequences of these whitespace characters are collapsed (based on 'white-space' value) at rendering time.
"To my mind there shouldn't BE any whitespace text node in the above example because that whitespace is outside the tag, not inside it."
In situations where you're inserting linefeeds between markup in the source, whitespace text nodes will be inserted at the end of each line in the DOM - one of the reasons why this behavior is required, is to allow 'white-space: pre' to work. After DOM parsing, the 'white-space' processing model dictates whitespace collapsing, based on whitespace character sequences in whitespace-only text nodes.
"It seems like the whitespace property isn't getting much attention"
Yes. On the surface, it seems a fairly trivial mechanism to implement. I'm not sure why conversation on feature definition hasn't really begun yet.
[1] http://www.w3.org/TR/CSS21/text.html#white-space-model
Great article! I always wondered, that an element is inline, inline-block or block element. In the HTML4 default StyleSheet it has an inline display property. This is ok, because if you write something like "text text" (note the spaces surrounding the element), there will be the whitespace. But if is inline, you're not able to set it's width and height, but you can! So it must be an inline-block, but than there should not be whitespaces.
But as I can remember back to the old days, when we used s, then we wrote nn, there wasn't any whitespaces. So what is the difference between
#text ("text")
#text (s)
IMG
#text (s)
#text ("text")
and
TD
#text (n)
IMG
#text (n)
/TD
?
I ran into this article from Google and others may as well. If you want to suppress white space but are still concerned about your source layout being organized, you can use comments to handle the indentation:
loremipsum
Still not ideal, and the file size is increased, but it may be useful.
Whoops, wasn't sure how the comment system would format. Is this better?
<ol><!–
–><li>Lorem<!–
–><li>Ipsum<!–
–><ol>
Well never mind. Hopefully you get the idea.