The Fix
Don't mix, embrace the table!
"Fixes" it on Firefox (tested 31.2.0) and IE 8, and is honestly more semantically correct.
.a{ display:inline-table; max-width:45%; }
.b{ display:table-cell; padding-right:5px;}
.c{ display:table-cell; }
<span class="a">
<span class="b">b</span>
<span class="c">c1 c2</span>
</span>
<br /><hr /><br />
<span class="a">
<span class="b">longer</span>
<span class="c">Bacon ipsum dolor amet excepteur laboris irure, corned beef minim pastrami venison in anim incididunt strip steak ea non doner.</span>
</span>
Why There Was An Issue
The problem with your original code is that Firefox takes the floated element completely out of flow when calculating its shrink-to-fit sizing. While float
s affect in-flow content width, they themselves are not in-flow, and thus, are merely taking the horizontal space from the rest of the content- causing the behavior you were seeing
Here is a demonstration of what is happening (view in Firefox to actually see it). Note that outline
s are used on .a
and .c
but a thick border
(which actually takes up space) is used on .b
.
.a { display: inline-block; outline: 1px solid blue; }
.b { float: left; border: 5px solid green; }
.c { display: table; outline: 1px solid red; }
<span class="a">
<span class="b">b</span>
<span class="c">c1 c2</span>
</span>
<br />
<span class="c">c1 c2</span>
This is by design, not a bug, and checking the current spec, the basic box model working draft, and the spec regarding calculating widths you'll find that floats are noted as out-of-flow, and the spec regarding block-formatting and inline-formatting explicitly states that float
s are part of an inline-context width, but does not for a block-context (the inside of an inline-block
). Thus, Firefox is actually behaving according to a strict interpretation of the spec- this is technically a bug in the other browsers.
Yet, there is still an issue with how Firefox does this.
If we make the float larger than our in-flow content (and switch back to borders as outlines include overflowing children; I've shifted the sibling red left by 1px so it will line up with its nephew clone) (again, view in Firefox)
.a { display: inline-block; border: 1px solid blue; }
.b { float: left; border: 5px solid green; width:200px; }
.c { display: table; border: 1px solid red; }
.d { position:relative; left:1px; }
.e { max-width:100px; }
<span class="a">
<span class="b">b</span>
<span class="c">c1 c2</span>
</span>
<br />
<span class="c d">c1 c2</span>
<br />
^^^ without <em>.a</em> having a width limit
<hr />
vvv with <em>.a</em> having a width limit
<br />
<span class="a e">
<span class="b">b</span>
<span class="c">c1 c2</span>
</span>
<br />
<span class="c d">c1 c2</span>
The blue box is stretched to contain its entire green child, even though, according to the strict interpretation of the spec, it is supposed to overflow instead. THIS is a bug with Firefox, as floats are only supposed to affect parent width:auto
in an inline context. In a block context, which the inside of an inline-block
is supposed to be, the width of floats is not included.
Note, this is also how most other browsers behave (to a degree- Firefox will size the parent to the float
's box width, while other browsers will put the in-flow next to it if the parent can still grow), and that if you provide any width
values or limits on .a
(ala .e
in my example), you get the expected behavior (as shown) of the green float overflowing its parent (should be the case in all browsers, as all of these behavioral issues are based on width:auto
).
Credits
Many beers to Oriol (poster of the other answer)- if I didn't start arguing with him on this, I wouldn't've had a reason to actually get into the specs and figure out what was really happening. Also credit to him for pointing out Firefox did still mis-render it- that entire chunk was thanks to him.