Why doesn't vertical-align: middle work with i

2019-07-14 03:25发布

问题:

Here is my code:

*               { vertical-align: top; margin: 0; }
td              { vertical-align: middle; border: 1px solid red; }
td:nth-child(1) { line-height: 3em; }
td:nth-child(2) { line-height: 4em; }
td:nth-child(3) { line-height: 0.1em; }
p, input        { outline: 1px solid green; }
<table>
    <tr>
      <td>
        <p>
          Some vertically centered text.
        </p>
      </td>
      <td>
        <input type="text">
      </td>
      <td>
        <input type="text">
      </td>
    </tr>
</table>

As one can see, the p is neatly vertically centered, as well as the input with line-height: .1em, while the input with line-height: 4em is moved to the top.

I did not find an explanation for this behaviour after lengthy research.

I set up a jsfiddle: https://jsfiddle.net/dlenne/8xapwz11/14/.

回答1:

You've set vertical-align: middle on the td, each of which is a parent of an input element.

But the vertical-align property is not inherited (source).

So, one solution is to apply the rule directly to the inputs:

*               { vertical-align: top; margin: 0; }
td              { vertical-align: middle; border: 1px solid red; }
td:nth-child(1) { line-height: 3em; }
td:nth-child(2) { line-height: 4em; }
td:nth-child(3) { line-height: .1em; }
p, input        { outline: 1px solid green; }
input           { vertical-align: middle; }               /* new */
<table>
  <tr>
    <td>
      <p>Some vertically centered text.</p>
    </td>
    <td>
      <input type="text">
    </td>
    <td>
      <input type="text">
    </td>
  </tr>
</table>

An alternative solution simply bypasses the line-height rules by switching the display value of the inputs from inline to block.

*               { vertical-align: top; margin: 0; }
td              { vertical-align: middle; border: 1px solid red; }
td:nth-child(1) { line-height: 3em; }
td:nth-child(2) { line-height: 4em; }
td:nth-child(3) { line-height: .1em; }
p, input        { outline: 1px solid green; }
input           { display: block; }               /* new */
<table>
  <tr>
    <td>
      <p>Some vertically centered text.</p>
    </td>
    <td>
      <input type="text">
    </td>
    <td>
      <input type="text">
    </td>
  </tr>
</table>

References:

  • Understanding vertical-align, or "How (Not) To Vertically Center Content"
  • 10.8.1 Leading and half-leading (W3C definitions for line-height and vertical-align)
  • Line-height inheritance


回答2:

Since the cell has vertical-align: middle, its contents will be aligned to the middle of the cell.

But in this case it's not noticeable, because the contents occupy all the cell vertically.

That's because the line-height property sets the minimum height of a line box, and you use a very tall value

td:nth-child(2) {
  line-height: 4em;
}

Then, the input is an inline-level element. So its vertical alignment with respect to that line box will be given by the vertical-align of the input.

* {
  vertical-align: top;
}

If you want to align the input at the middle of the cell, you should use vertical-align: middle on the input to align it to the middle of its line box, which is aligned to the middle of the cell.

input {
  vertical-align: middle;
}

* {
  vertical-align: top;
  margin: 0;
}
td, input {
  vertical-align: middle;
  border: 1px solid red;
}
td:nth-child(1) {
  line-height: 3em;
}
td:nth-child(2) {
  line-height: 4em;
}
td:nth-child(3) {
  line-height: 0.1em;
}
p, input {
  outline: 1px solid green;
}
<table>
  <tr>
    <td>
      <p>
        Some vertically centered text.
      </p>
    </td>
    <td>
      <input type="text">
    </td>
    <td>
      <input type="text">
    </td>
  </tr>
</table>



回答3:

I think its because of this :

*{vertical-align: top;}

When you make the line height bigger than the td(parent) it i.e. input(child) scales out and hence follows: vertical-align: top; rather than vertical-align: center;