Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Mysterious CSS vertical space

Tags:

html

css

xhtml

From this simple html.

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">

<html xmlns="http://www.w3.org/1999/xhtml">

<head>
  <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
  <title>Hello</title>
  <style type="text/css" media="screen">
    .t1 {
      padding: 0px;
      margin: 0px;
    }
    .popup {
      display: inline-block;
      position: relative;
      width: 0px;
      padding: 0px;
      margin-left: -0.5em;
    }
    .hint {
      position: absolute;
      z-index: 1;
      width: 20em;
      background-color: white;
      border: 1px solid green;
      padding: 0.5em;
      margin-top: 1em;
    }
    .list {
      padding: 0px;
      padding-left: 1em;
      margin: 0px;
    }
  </style>
</head>

<body>

<!-- properly layout -->
<div style="height: 10em;">
  <span class="t1">MyObject o = www.mycompany.project.ObjectFactory.</span>
  <div class="popup">
    <div class="hint">
      <ul class="list">
        <li>NewSimpleObject(int x);</li>
        <li>NewComplexObject(int x, int y);</li>
        <li>NewComplicateObject(int x, int y, intz);</li>
      </ul>
    </div>
    <div>&nbsp;</div>  <!-- no idea why, but ending space is required for proper layout -->
  </div>
</div>

<!-- incorrect layout -->
<div style="height: 10em;">
  <span class="t1">MyObject o = www.mycompany.project.ObjectFactory.</span>  
  <!-- mysterious vertical space appear here -->
  <div class="popup">
    <div class="hint">
      <ul class="list">
        <li>NewSimpleObject(int x);</li>
        <li>NewComplexObject(int x, int y);</li>
        <li>NewComplicateObject(int x, int y, intz);</li>
      </ul>
    </div>
    <!-- <div>&nbsp;</div>  -->
  </div>
</div>

</body>

</html>

Here is the result:

alt text http://img23.imageshack.us/img23/6224/resultrendering.png

The result is similar across browser. So I believe this is not a browser bug.

Where does the vertical space between the text-line and the popup-hint in the second rendering come from ? And how can the <div>&nbsp;</div> solve this problem ?

UPDATED:

Conclude from Richard M answer. Box with no content has no dimension (with an exception of Inline). The <div>&nbsp;</div> make "popup" dimension exists.

The better solution, according to Richard, is to use inline instead of inline-block. Since the vertical dimension of inline is the same regardless of its content existence

For some reason I don't know yet, the margin-top: 1em is no longer necessary when switch to "inline"

UPDATED 2:

OH NO.. This issue cannot be concluded yet. The change that Richard M suggest (use inline and remove margin-top) would work only with Webkit Browser (Chrome, Safari) On IE and Firefox , the popup box align to the left rather than to the text line.

The first sample in the question (inline-block & non-empty content) is probably the most reliable option for now.

UPDATED 3:

Conclusion ! The true cause of this issue originate from the fact that non-inline block with no content has no dimension. Richard M suggest using inline to avoid this issue. Unfortunately, I've found this solution inconsistence across browsers. I came up with another option in opposite direction, using inline-block with forced dimension via height: 1px; This work correctly in any browser.

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">

<html xmlns="http://www.w3.org/1999/xhtml">

<head>
  <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
  <title>Hello</title>
  <style type="text/css" media="screen">
    .t1 {
      padding: 0;
      margin: 0;
      width: 0em;
    }
    .popup {
      display: inline-block;
      padding: 0;
      margin: 0; 
      position: relative;
      width: 0;
      height: 1px;  <!-- force vertical dimension -->
    }
    .hint {
      position: absolute;
      z-index: 1;
      padding: 0;
      margin: 0;
      margin-top: 1px;  <!-- compensate for the setup dimension -->
      width: auto;
      white-space: nowrap;
      background-color: white;
      border: 1px solid green;
    }
    .list {
      padding: 0;
      padding-left: 1em;
      margin: 0.5em;
    }
  </style>
</head>

<body>

  <!-- properly layout -->
  <div style="height: 10em;">
    <span class="t1">MyObject o = www.mycompany.project.ObjectFactory.</span><!-- 
      whitespace is not welcome
    --><div class="popup">
      <div class="hint">
        <ul class="list">
          <li>NewSimpleObject(int x);</li>
          <li>NewComplexObject(int x, int y);</li>
          <li>NewComplicateObject(int x, int y, int z);</li>
        </ul>
      </div>
    </div><!--
      whitespace is not welcome
    --><span>(1, 2, ...</span>
  </div>

</body>

</html>
like image 280
Sake Avatar asked Feb 22 '10 15:02

Sake


3 Answers

It has to do with the fact that the div with the class popup is not the one with the position: absolute, but its child, hint.

From the browser's perspective, the popup div, when containing only hint, has no content, and thus, no dimensions. The <div>&nbsp;</div> gives it content and causes the hint popup to start properly on the top edge of the div- but why that is, still escapes me, even though I'm sure there is a perfectly logical explanation for it :)

like image 112
Pekka Avatar answered Nov 08 '22 18:11

Pekka


Your .hint div has a 1em top margin to "push" it down below the line of text, however in your second instance your .popup div doesn't contain anything (as absolutely positioned elements take up no space). An inline-block div with no content has no height or width and sits on the baseline of a line of text. So, you are "pushing" off the bottom rather than the top of the line, and hence the additional 1em vertical space. I don't really understand why you're using inline-block, inline would work just as well given the content of the div is absolutely positioned.


In response to your question edits: Using display inline as I suggested should work, but you need to set the left and top values of your absolutely positioned .hint div to zero. Also, you'll need to remove your <div>&nbsp;</div> element otherwise you'll end up with a line break where it occurs (because it's not inline).

like image 21
Richard M Avatar answered Nov 08 '22 16:11

Richard M


Could it be the real intention is:

<div style="clear:both;"></div>

instead of just:

<div>&nbsp;</div>
like image 3
bcosca Avatar answered Nov 08 '22 17:11

bcosca