What is the difference between block and inline-block with width: 100%? - css

I've recently been trying to figure out when it is appropriate to use inline-blocks. They seem to be far more useful than just a block element. In fact, an inline-block element seems to be able to do anything a block element can do, but with a little extra styling.
Is there any reason an element with display: inline-block; width: 100%; is any different than an element with display: block;? (Aside from the fact that one is longer?)
I've been researching this topic by reading the w3c recommendation. I can't seem to find a difference.

What you said is pretty much correct: "an inline-block element seems to be able to do anything a block element can do, but with a little extra styling." This is mostly due to the fact that the one thing both have in common is the fact that they are both block containers.
However, there's a catch.
A block box participates in a block formatting context, and an inline-block participates in an inline formatting context (although it establishes a block formatting context for its descendants, just like a block box does under certain conditions). See section 9.4. Basically, this means an inline-block is treated as though it were text, which in turn means most properties that usually apply to text would also apply to an inline-block. These properties include text-indent, text-align and vertical-align, among others.
This can cause undesired side effects which you can easily prevent by not using display: inline-block in the first place. See this question for an interesting example of what can happen.
The box model for inline-blocks also differs somewhat from that of block boxes. Section 10 contains all the nitty gritty details, but the main differences are:
Without the width: 100% declaration, as you may have suspected, an inline-block will shrink to fit its contents.
Because an inline-block flows inline, you can't center it with auto left and right margins. You use text-align: center instead. It goes without saying that it must then be on its own line with no text surrounding it on the same line, but if you're setting width: 100% then this won't be a problem.
Inline-blocks are never affected by margin collapse.
If you're trying to create a block-based layout, you should be using display: block. Generally speaking, when deciding between the two, you should always default to display: block, and only choose display: inline-block if you have a very good reason to (and no, blocking margin collapse is not what I would consider a good reason).

I'd echo everything said by #BoltClock; he makes a lot of good points.
I would also add to this that because an inline-block is treated as text, the surrounding white space is also treated as text and thus comes into play in ways that it wouldn't for a block element. This frequently catches people out when trying to use inline-block for layout. This is probably the biggest 'gotcha' for using inline-block.
Another slightly more subtle point applies specifically in your case, ie when setting width:100%. In this case, you need to beware of which box model you're using, as the standard box model puts your borders, padding and margins outside of the element's width. Thus if you use borders, padding or margin your element will actually take up space a little bit more than 100% width.
This point applies equally to block and inline-block elements, but is more likely to occur with inline-block because the difference is that block doesn't normally need to be set to width:100% because it defaults to expand to fill the width anyway, and without the box model causing it to go over the edge.
To avoid this, you could switch the box model by using box-sizing:border-box, so that the borders etc are placed inside the box, and thus if you ask for with:100%, that's what you'll get. See the MDN box-sizing page for more info.

Related

How can I reserve space for visibility: hidden elements when they are also position: absolute?

I want to have a region of my page that is reserved for context sensitive help text. It is blank, except when hovering over certain particular elements. But, of course, there are several independent pieces of text from which the visible selection might be chosen. This is in a page flow, with more stuff below it. I tried using a div "positioned", and putting help divs inside that. Each of the help divs is position: absolute; top: 0px; visibility: hidden; with the intention that JS would make one of them visible at a time, yet the space would have been reserved for the biggest piece of text in any of the help divs. Well, as most of you have guessed, because the help divs are position: absolute, their heights don't affect the height of the enclosing div, which ends up at a height of zero.
how can I achieve this? I don't want to use pixel sizing to force a height, because it's almost always wrong on some browser/font combination, and would be a bear to keep tweaking every time the help text were changed, or a new, longer help segment gets added to this.
Did I make sense, or do I need to try to draw pictures?
Yep, you're making sense. As you indicate correctly the containing element is collapsing to zero height since it doesn't contain any flow children with size. There is no simple solution to this without resorting to Javascript as obvious alternatives mean making all of them part of the flow layout, meaning the container would grow to accomodate all of the texts.
Solutions that would work:
Apply display:inline-block to all of the help texts to put them next to eachother, put them in a container element that has a width of 10000px or more as required, and encapsulate that element in a container with overflow:hidden. This way the container will actually assume the height of the largest child. Activating a text would then require moving the element in the DOM to the front so it is drawn first, or scrolling to bring it to the right position, which could be complex.
After loading the page use Javascript to measure the actual heights of the elements, set the largest one as the height of the container, and then apply display:none to the children instead of visibility:hidden.
The second option is easiest, and would be my preferred choice. It all depends a bit on your specific case though whether there's a better alternative.

CSS overflow property

I've found some CSS templates where some classes have the overflow:hidden property, but no size defined. If I recall correctly, block elements stretch to fit their content unless otherwise specified. Since this is not the case, I feel that putting the overflow:hidden is pointless and I can delete it without hesitation. Is this right or am I missing something?
While that's the main purpose of the overflow property, it's not the only effect it has on rendering. The other major effect it has is that setting overflow to anything other than visible (the default) causes a block box to establish its own block formatting context.
This is mainly used to contain floats without the need for a clearfix; however that isn't the only effect of having a new BFC; there are a number of other corner cases that are better described elsewhere in the spec. Also see this lengthy write-up on the reasoning for this behavior (which, oddly enough, has very little to do with containing floats; that actually ends up being nothing more than a side effect).
So if you remove that overflow declaration, you may break float layouts, among other things. I suggest avoiding doing so unless it's absolutely necessary or you're sure it won't affect the layout.
If there are floating children inside that div, then overflow: hidden is probably there to contain them.
overflow: hidden creates a new block formatting context, and elements that create new block formatting contexts contain floats.
It may depend. if your div contains some floated elements you could use
div {
height: auto;
overflow : hidden;
}
as a workaround for the clearing. So I wouldn't delete that rule without seeing the effect on the layout
overflow:hidden can come in handy if you have a child element with a width specified which is greater than the container's max allowed width. Otherwise it will stretch the container.
See example
A common use of this is when displaying a carousel, with floated child elements. The elements need to appear inline, but hidden, so that they can come into vision when the left CSS property is changed.

Div Wrapping In IE6 Only

You can see the issue here: http://jsfiddle.net/6WuVz/7/
This works in all other browser (image top) but when viewed in ie6 (image bottom) it wraps incorrectly:
Note: You can see this in later versions of IE by using compatibility view and selecting IE5 Quirks.
From what I can tell, the div that holds your title doesn't have a set width. Therefore, IE is telling it to expand, and as it expands, it shifts downward, where there's space. Try setting a width for IE6 only and see if that fixes it.
Additionally, IE6 has some issues with overflow: hidden. Though it's usually in combination with position: relative, you may be running into something similar. If the previous solution doesn't work, you could try this.
Edit - Since you don't want to set an explicit width, I've thought of a few other options left to you:
Explicitly set clear: none on the non-floated element
Use a span element instead of div for the text in question (span is inline, while div is block, so it shouldn't expand to the parent width; given what you're doing, it probably makes more semantic sense to use span, anyway).
Use JavaScript to determine the width of the floated div for IE6, and set a size on the non-floated div accordingly (again, you can use conditional comments in your HTML to target IE6 exclusively)
Seriously consider whether it's worth supporting IE6 (ie - if this is on a site where the audience is fairly tech-savvy, you can probably forego IE6 support entirely, or at the very least, fixing this problem will cost your project more than the returns you get; but if you're dealing with healthcare providers, you probably have to still deal with IE6).
IE6 has a non-standard box model, which tells block-level elements to expand the full width of their container, instead of "shrink-wrapping" to their content. Their content is larger than the width they're allowing, and the float property takes the floated elements out of the document flow (which is why your overflow: hidden, when turned to overflow: visible, runs over top the floated content). The newer browsers have basically an "updated definition" (so to speak) of the float property, which tells sibling content to flow around the floated element, in addition to taking it out of the normal document flow. CSS-tricks has a good article on float, as does A List Apart, if you need more information.

Firefox and flexbox - When using white-space: nowrap on child element the flexible box breaks

Take a look at this jsFiddle in Safari or Chrome, then in Firefox: http://jsfiddle.net/brandondurham/LRJhm/
What it looks like in Webkit: http://cloud.smallparade.com/B4TE
What it looks like in Firefox: http://cloud.smallparade.com/B53R
You'll see the flexible box is broken in Firefox. The longer of the two boxes (.left) has the css property white-space set to nowrap because, well, I don't want it to wrap. This single property is making the flexible box break and extend to fit the entire contents of the .left div.
Anyone else seen this behavior? Have a fix?
While I think the accepted answer by robertc is correct (in that is how box flex is supposed to work). You can disable the "intrinsic" width he talks about by setting that width of the box explicitly to 0. This way, only your specified distribution of the widths is taken into account.
This behaviour can be explained, because, when you set all the box widths to zero, then all of the width will become "remaining", thus the distribution depends completely on what you specify.
Set width: 0 on the element and that will become it's "preferred width", and will make non-wrapping text items inside the element behave correctly.
http://lists.w3.org/Archives/Public/www-style/2011Jan/0201.html
That's how it's supposed to work. Flexbox distributes the left over space after the intrinsic width of the elements has been calculated, it does not control the intrinsic width of the elements themselves. This is why the results are unintuitive if you don't set explicit widths on things, though the working group is reviewing the spec.
My advice would be to try using display: table; instead, though you may encounter some similar issues.

Why does setting overflow alter layout of child elements?

In this question someone was having a layout problem because they had two floated divs inside a non-floated div. I suggested adding float: left to their outer div, which does fix the problem. Someone else suggested adding overflow: hidden, which to my surprise, also worked.
This doesn't seem at all like the purpose of of overflow: hidden. Clearly overflow: hidden causes elements to view their children differently somehow. What I'm really trying to understand is what that difference is. Intuitively it should only make the element smaller than it would otherwise be, never bigger and I don't see why it would affect the layout hierarchy.
Can anyone explain why this would be correct/necessary behavior or if this is just a browser quirk? Is their another facet to the overflow property I'm missing? Is either solution any better than the other?
Edit: I've discovered setting overflow: auto works too, so it doesn't seem to be the value of overflow that's important, just that it's set. I still don't understand why.
Overflow of anything but visible creates a new block formatting context which causes floats to be contained. It's standard behaviour.
Floats, absolutely positioned
elements, inline-blocks, table-cells,
table-captions, and elements with
'overflow' other than 'visible'
(except when that value has been
propagated to the viewport) establish
new block formatting contexts.
In a block formatting context, boxes
are laid out one after the other,
vertically, beginning at the top of a
containing block. The vertical
distance between two sibling boxes is
determined by the 'margin' properties.
Vertical margins between adjacent
block boxes in a block formatting
context collapse.
In a block formatting context, each
box's left outer edge touches the left
edge of the containing block (for
right-to-left formatting, right edges
touch). This is true even in the
presence of floats (although a box's
line boxes may shrink due to the
floats), unless the box establishes a
new block formatting context (in which
case the box itself may become
narrower due to the floats).
Floating items removes them from the normal layout in many cases. It's not exactly like or unlike position: absolute; in that. Block items tend to ignore floated items (including block items that contain the item), but unlike position: absolute; items, floated ones are recognized and wrapped around by inline items, like text.
Having the wrapping item (div or otherwise) also be floated causes it to behave differently related to floated items it contains. Having the wrapping item set to overflow: hidden; forces it to consider the items it contains differently, as well. My guess is it's just a happy coincidence that the end result here appears to be the same. Not a quirk or bug... just how it works out.

Resources