tags:

views:

611

answers:

5

From this simple html.

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

<html xmlns="http://www.w3.org/1999/xhtml"&gt;

<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

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"&gt;

<html xmlns="http://www.w3.org/1999/xhtml"&gt;

<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>
A: 

You can adjust your margin-top on the hint. You can set it to a negative value if needed to correct the alignment.

Diodeus
Yes, but that doesn't really solve the mystery of why the rendering differs, does it?
Pekka
A: 

If you delete the margin-top: 1em; the second layout will work.

EDIT: replace margin-top: 1em; with overflow: auto; and you don't need the div anymore.

Burntime
But the first one will fail then.
Sake
+4  A: 

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 :)

Pekka
I believe that popup having no content or dimensions is causing the problem. You can correct it by leaving the <div> there or by setting the height of .popup explicitly (It can be any small value. I tried 10px and it worked fine.)
takteek
@takteek true. What I find fascinating is why a popup with *no* content will cause the starting point for `hint` to move down 1 line, but a popup *with* content will not. This is a really tricky edge case. Anyway, it can be fixed using the methods you mention.
Pekka
+3  A: 

Could it be the real intention is:

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

instead of just:

<div>&nbsp;</div>
stillstanding
Wow.. clear:both make both sample work ! No idea why. Would you please explain more ?
Sake
it's pretty much like adding a carriage return after the floating objects above it, which means you're clearing your workspace below them.
stillstanding
Hmm.. from Pekka answer, it looks like ANY content inside "popup" will do. "clear:both" shouldn't have any effect in this case.
Sake
@rockjock I believe there are no "float" involve in my case.
Sake
but <span> and .popup are inline blocks, so you really don't have to specify float. They're already floating.
stillstanding
It's floating but it's definitely not a "float". :)
Sake
+3  A: 

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).

Richard M
You mean I should use <div style="display: inline"> ?
Sake
Yes, change to display inline and remove the 1em top margin and your two cases will be laid out be the same.
Richard M
Yes it work ! Thanks.
Sake
The empty "inline-block" have no height. But the empty "inline" share the same height as its preceding.. Is that the proper takeaway for this lesson ?
Sake
Yes, that is the case as far as I understand it. The height of an inline element is equal to the line-height of the containing element, while an inline-block element has no intrinsic dimensions.
Richard M
+1 Good Job!!! Didn't know empty `inline-block` elements behave that way.
Pekka
Just notice that your vote is decrease. I have no idea why, however Richard M answer is absolutely correctly explain the cause of this issue. (Although, his latest suggestion is not actually work :)
Sake