Search code examples
cssvertical-alignmentcentering

Avoid vertical-align: middle extending height of containing block


Given the following (also on JSFiddle):

div {
    font-size: 28px;
    outline: 1px solid red;
    width: 40%;
    float: left;
    line-height: 36px;
}
div:first-child::before {
    content: "Hi!";
    display: inline-block;
    vertical-align: middle;
    outline: 1px solid blue;
    font-size: 8px;
}
<div>xHello, world!</div>
<div>xHello, world!</div>

The second div (i.e., that without the vertically aligned middle content) is 36px high (as one would expect; the single line box within it has a height of 36px, per line-height).

The first div is 39px high here (with subpixel rendering, some slight variation is expected here, so 39px/40px are both reasonable expectations), as the line box of the content ::before it extends beyond the 36px of the "normal" content, due to its vertical alignment. How can I get the containing block (i.e., the div) to extend only to 36px high (assume I'm not concerned about the content ::before overflowing it)?

The typical approach of taking it out of the normal flow doesn't work here as then it ceases to be vertically aligned. Given the height of a block level element is dependent upon the bottommost line box within it, is this even plausible?


Solution

  • The ::before element inherits the 36px line-height. As far as I understand, it does not need that line-height since you are using vertical-align method of centering text. In fact, this unnecessarily tall line height is causing the issue. Reset it:

    div {
      font-size: 28px;
      outline: 1px solid red;
      width: 40%;
      float: left;
      line-height: 36px;
    }
    div:first-child::before {
      content: "Hi!";
      display: inline-block;
      vertical-align: middle;
      outline: 1px solid blue;
      font-size: 8px;
      /* the line height is inherited, reset it */
      line-height: normal;
    }
    <div>xHello, world!</div>
    <div>xHello, world!</div>