36

jsFiddle Demo

I cannot seem to figure out why using display:inline-block would cause this <div> element to somehow gain height when its containing element was hidden. This does not happen with display:block.

html:

<div style="display:inline-block;"><input type="hidden" /></div>
<div>Gap above created by inline-block</div>
<div style="display:block;"><input type="hidden" /></div>
<div>No gap above if using block</div>

screenshot of jsfiddle

Why does display:inline-block cause the gap depicted here?

Travis J
  • 77,009
  • 39
  • 185
  • 250
  • 1
    This question seems to be similar: [A Space between Inline-Block List Items](http://stackoverflow.com/questions/5256533/a-space-between-inline-block-list-items) – Rocket Hazmat Nov 20 '13 at 20:37
  • 1
    @RocketHazmat - Perhaps similar, but a duplicate? Definitely not. If they are all on the same line the behavior is the same. – Travis J Nov 20 '13 at 20:39
  • I think the "gap" is because there is no data inside the `
    `. Check this out: http://jsfiddle.net/FE3Gy/17/
    – Rocket Hazmat Nov 20 '13 at 20:49
  • @RocketHazmat - You are correct that if other content joins it then it does not go after it. But why would no data cause the height to exist? Span certainly doesn't act like that: http://jsfiddle.net/FE3Gy/22/ – Travis J Nov 20 '13 at 20:52
  • 2
    `` is `inline`, not `inline-block` :-) – Rocket Hazmat Nov 20 '13 at 20:55
  • 1
    I guess it's related to this "Inline-level elements are those elements of the source document that do not form new blocks of content; the content is distributed in lines" No content still means it distributes a line (an empty line) - http://www.w3.org/TR/CSS2/visuren.html –  Nov 20 '13 at 20:56
  • @Layne - Can you add this link and your description as an answer? – Travis J Nov 20 '13 at 21:05
  • A good answer to this is http://stackoverflow.com/a/27536461/1173555 – Martin Connell Feb 10 '17 at 00:13
  • Using vertical-align is not really an "answer" to the fact that inline blocks create atomic inline boxes. – Travis J Feb 10 '17 at 00:28
  • @ThomasMaier - That is inaccurate. inline-block elements do not behave "like words", the analogy breaks down when the element has a height and width of 0. A word with no height or width takes up no space, whereas the inline-block element shown here, if used with height:0, width: 0 will still take up space. The issue lies in the fact that the inline-block element will intrinsically create a container. The w3 link explains it perfectly. – Travis J Sep 21 '17 at 07:28

7 Answers7

41

One thing that happens when you create a display:inline-block is that the line-height calculations will change:

In an inline formatting context, boxes are laid out horizontally, one after the other, beginning at the top of a containing block. Horizontal margins, borders, and padding are respected between these boxes. The boxes may be aligned vertically in different ways: their bottoms or tops may be aligned, or the baselines of text within them may be aligned.

source: http://www.w3.org/TR/CSS2/visuren.html#block-formatting

The height of each inline-level box in the line box is calculated. For replaced elements, inline-block elements, and inline-table elements, this is the height of their margin box; for inline boxes, this is their 'line-height'.

source: http://www.w3.org/TR/CSS2/visudet.html#line-height

CSS assumes that every font has font metrics that specify a characteristic height above the baseline and a depth below it. In this section we use A to mean that height (for a given font at a given size) and D the depth. We also define AD = A + D, the distance from the top to the bottom.

source: http://www.w3.org/TR/CSS2/visudet.html#inline-box-height

So the line height will be defined on their font type. However when the inline-block is empty it will have its basic line-height. It however still tries to generate his line-height with a font.

To quick fix this you can use a wrapper which defines exclusive that there is no font, so no line-height which leads into no height:

.wrapper
{
    font-size: 0;
}

Where you can reset this property in your inline-block:

.wrapper div
{
    font-size: medium;
}

Where the default value of font-size is medium.

jsFiddle

This way you can still use content in the inline-block without there being a gap.


Update

This update is because of Kevin Wheelers comment

... I'm confused, it still never says what the height of an empty inline-block element is. ...

I want to note that I have not found any official documentation about this, though through testing I have found common patterns.


Short version:

Just think of it as inline-block expects content and reserves a minimum line space based of the known line-height.


Some more insight:

JsFiddle as a more clear example

As you can see the gab of the inline-block height is based on a line-height, which we have determed in the first post.

Now where does this line-height come from?

It is inherited from the first that determs the line-height: the <body> element.

You can test this my changing font-size, font-family or the line-height of the <body> element.

So it reserves a line-box for it's content. Which is strange that it is visible at all, as you can see according to the W3 specs of inline-formatting:

Line boxes that contain no text, no preserved white space, no inline elements with non-zero margins, padding, or borders, and no other in-flow content (such as images, inline blocks or inline tables), and do not end with a preserved newline must be treated as zero-height line boxes for the purposes of determining the positions of any elements inside of them, and must be treated as not existing for any other purpose.

It does this for every other element inside of the inline-block, but it always seems to reserve a minimum line space.

nkmol
  • 7,706
  • 3
  • 25
  • 47
  • I believe this is a better answer than the one selected as it no only shows exactly why the issue occurs it also show how to get around the problem. I know that the original question didn't ask how to get around it but I am sure this is what they wanted and will defiantly be what others want to know when they find this question. Thanks :) – GazB May 30 '14 at 08:38
  • @GazB - While I did upvote this answer for containing proper information about inline-block, it unfortunately does not address the problem in the question. The problem was the **inline** element, not the inline-block. The **inline** element (the hidden input) was generating a line block. Using `font-size:0` will take precedence for child elements and essentially make the line block from the inline element 0 height, but it is a hackish solution and that is both not what I wanted nor ended up using. – Travis J Jan 27 '15 at 18:16
  • @TravisJ The reason why i focused on the inline-block is because when you remove the hidden content, it still has the gap. As inline-blocks aren't used to be empty. http://jsfiddle.net/FE3Gy/49/ What solution did you come up with then? ^^ – nkmol Jan 27 '15 at 19:12
  • 1
    @nkmol - I think your answer is a good workaround for something which would be done quick. However, this sample was just a reproduction. The scenario which spawned it was part of library I was making to support an ajax search box and it was containing a hidden input. The intention was to store the hidden inputs in their own div, but that was excessive and led also to this type of corner case. As a result, the hidden inputs were moved to be in the same space as the visible input (since hidden wont affect the layout there anyway). This also resulted in less required markup. – Travis J Jan 27 '15 at 19:20
  • This solution didn't work for me but thanks for the explanation. inline-blocks just use up more space. – obesechicken13 Apr 15 '15 at 21:49
  • `for inline-block elements, and inline-table elements, this is the height of their margin box; for inline boxes, this is their 'line-height` -- I'm confused, it still never says what the height of an empty inline-block element is. The end of the quote about line-height doesn't apply, because inline block elements don't create inline boxes. They are inline-level boxes, but not inline boxes. – Kevin Wheeler Jul 16 '15 at 01:58
  • @KevinWheeler Its been some time, but i totally agree on you there. I've made an update to state this somewhat clearer. I start to think this isn't the right behaviour according the the W3 specs, can't say with certainty. I hope it is clear now, how it behaves and when you want to use it (Don't think it is that important to know the nitty-picky specifics for most). Thanks! – nkmol Feb 25 '16 at 14:50
7

Ok as already mentioned very briefly in the comments:

inline-block

This value causes an element to generate an inline-level block container. The inside of an inline-block is formatted as a block box, and the element itself is formatted as an atomic inline-level box.

inline

This value causes an element to generate one or more inline boxes.

The most important part for this topic would be that the element itself get's formatted not just the content. Every inline-block element will be seen as atomic inline box and thus take up space.

Source: http://www.w3.org/TR/CSS2/visuren.html#inline-boxes

Community
  • 1
  • 1
  • 1
    So is there a good work around? This mucks up transitions quite a bit, especially when we have divs with unknown heights. – Costa Mar 10 '16 at 23:43
5

Apparently what display:inline-block does for default is set a visual height based on his parent line-height. The solution make a parent wrapper with this properties:

#container {
  line-height:0;
}

The demo http://jsfiddle.net/FE3Gy/33/ . Here you can check an example with different font-size values.

Acorrding to the W3 is:

The inside of an inline-block is formatted as a block box, and the element itself is formatted as an atomic inline-level box.

About inline box here

The width of a line box is determined by a containing block and the presence of floats. The height of a line box is determined by the rules given in the section on line height calculations.

So you can check more about line-height here :

http://www.w3.org/TR/CSS2/visudet.html#line-height

DaniP
  • 36,081
  • 8
  • 59
  • 70
3

You'll get an actual line whether you have a hidden input or a space or whatever - your browser thinks it's some inline content, therefore it gets a line.

http://jsfiddle.net/FE3Gy/7/

<div style="display:inline-block;"> </div><div>Gap above created by inline-block</div>
<div style="display:block;"><input type="hidden" /></div>
<div>No gap above if using block</div>

Even if you have absolutely nothing, you'll get a line. display: inline-block turns it into inline-content.

http://jsfiddle.net/FE3Gy/15/

Nate
  • 4,310
  • 2
  • 23
  • 24
  • It does, indeed! http://jsfiddle.net/FE3Gy/15/ I updated my answer to clarify that point. – Nate Nov 20 '13 at 20:48
1

Layne and Nate have the right answer, but I wanted to bring to your attention this clause from the CSS 2.1 spec, section 9.4.2.

Line boxes are created as needed to hold inline-level content within an inline formatting context. Line boxes that contain no text, no preserved white space, no inline elements with non-zero margins, padding, or borders, and no other in-flow content (such as images, inline blocks or inline tables), and do not end with a preserved newline must be treated as zero-height line boxes for the purposes of determining the positions of any elements inside of them, and must be treated as not existing for any other purpose.

Spans (inline elements) that have no in-flow content (<input type="hidden" /> is display:none so cannot be treated as in-flow content) meet those criteria so their containing line-boxes are treated as 0 height or non-existing. inline-block elements are explicitly excluded from meeting those criteria so the inline-block element creates a line box that must be line-height tall.

Note that you can see this in action in another way by adding a border to a span element so that it doesn't comply with the above criteria. See http://jsfiddle.net/FE3Gy/36/

Alohci
  • 70,004
  • 12
  • 103
  • 143
0

display:inline-block has different behavior than display:block. While block create a box element, inline block creates a box but it add some surrounding content as if it were a single inline element. This surrounding content could be the source of your issue. I think unless you have a very specific reason to use inline-block you should use display:block.

camicano
  • 19
  • 1
0

As cited above by @nkmol, its does carry default font size and line height causing unnecessary height for the parent. In some cases, line-height: 0 does solve the problem. But sometimes, in exceptional cases like an empty tag inside a parent

<div>
<a href=''></a>
</div>

I above case, just setting the font-size: 0 or line-height: 0 doesn't solve the problem as the a tag.

vertical-align: middle;

fixes the problem in such a case.

mib200
  • 1
  • 1