How can I mix vertically-centered elements with different font sizes and retain consistent line height?


Tags: html,css,html5,css3

Problem :

When you mix font-sizes of elements with vertical-align: middle inside of a container, the container's height can be larger than the line-height or height of either individual element. Here is a fiddle:

body {
  line-height: 20px;
  font-size: 14px;
}
.smaller {
  font-size: 0.9em;
  vertical-align: middle;
}
<div class="body">
  <div class="why-not-twenty-px">
    containing div has height <span class="smaller">&bull;</span> of 21px, not 20px
  </div>
  <div class="why-not-sixty-px">
    containing div has height of 61 px, not 60px multiline multiline multiline multiline multiline multiline <span class="smaller">&bull;</span> multiline multiline multiline multiline multiline multiline multiline multiline multiline multiline multiline multiline multiline multiline multiline multiline multiline multiline multiline multiline multiline
  </div>
</div>

In this example, the two containing divs are 21px and 61px instead of 20px and 60px.

How can I retain a container height that is a multiple of the line-height when mixing in an element like .smaller? .smaller must be vertically centered on the line. Ideally, any solution would only involve CSS changes to .smaller.



Solution :

§10.8 explains how the height of the line boxes is calculated:

As described in the section on inline formatting contexts, user agents flow inline-level boxes into a vertical stack of line boxes. The height of a line box is determined as follows:

  1. The height of each inline-level box in the line box is calculated. [...] For inline boxes, this is their 'line-height'

    Since .smaller inherits line-height: 20px and is an inline box (i.e. non-replaced with display: inline), its height is 20px

  2. The inline-level boxes are aligned vertically according to their 'vertical-align' property.

    .smaller has vertical-align: middle, which means

    Align the vertical midpoint of the box with the baseline of the parent box plus half the x-height of the parent.

  3. The line box height is the distance between the uppermost box top and the lowermost box bottom.

So both the text and .smaller have a height of 20px, but they have different alignment. Therefore, the line box grows:

enter image description here

Then, as other answers explain, a way to solve the problem is reducing .smaller's line-height:

enter image description here

However, there is an alternative solution, without modifying line-height: negative margins can be added to prevent .smaller from increasing the height of the line box.

As quoted above, the height of an inline box is its line-height, so to make the margins work, display: inline-block is also needed:

The height of each inline-level box in the line box is calculated. For [...] inline-block elements [...] this is the height of their margin box.

Note this solution won't break the alignment, because since .smaller has vartical-align: middle, if we use the same amount in margin-top and margin-bottom, it will remain centered.

enter image description here

To summarize, you can use this code:

.smaller {
    vertical-align: middle;
    display: inline-block;
    margin: -1em 0;
}

body {
  line-height: 20px;
  font-size: 14px;
}
.smaller {
  font-size: 0.9em;
  vertical-align: middle;
  display: inline-block;
  margin: -1em 0;
}
<div class="body">
  <div class="why-not-twenty-px">
    nor<span class="smaller">&bull;</span>mal
  </div>
  <div class="why-not-sixty-px">
    multiline multiline multiline multiline multiline multiline <span class="smaller">&bull;</span> multiline multiline multiline multiline multiline multiline multiline multiline multiline multiline multiline multiline multiline multiline multiline multiline
    multiline multiline multiline multiline multiline multiline multiline multiline multiline multiline
  </div>
</div>


    CSS Howto..

    How to line up lists side by side?

    How to make my a scalable website with auto:height and overflow:auto

    How to add conditional formatting to list items in CSS

    How to insert line breaks between numbers and content in ordered list

    How to switch between css with jquery

    How do I create two columns using CSS?

    How to mix 100% height with a minimum height

    How to load CSS using jquery

    how to create divs rowwise in css

    On Eclipse-Java EE, how do I change the color settings for selected elements on a tree view?

    How to fix “Eliminate render-blocking JavaScript and CSS in above-the-fold content” in joomla

    jQueryUI Autocomplete: how to use 'first-of-type' and 'last-of-type' with #ui-active-menuitem?

    How to customize responsive columns and inputs fields in twitter bootstrap?

    How do I make a textarea resize properly when I resize browser window?

    Is there a plugin for Wordpress that lets me show HTML/JS/CSS examples? [closed]

    how to change a css class style through javascript?

    How to display text left side and icon on right side in html css?

    How can I add interactive content to a Bootstrap popover?

    How to resize and float right a background image using css?

    How to get this partially diagonal shape from an image in CSS

    How to make this in html and css?

    How to Change Style of Parent
  • on Hover
  • How read(get) css style value of a server-side div in code behind(not set)?

    How to embed SVG styling with javascript?

    How to create shadow in JSF input field

    How to add hover class to jQuery click(function() accordian divs?

    how to make a div to wrap two float divs inside?

    how to set CSS border-left outside of box

    Show/Hide inline Form

    How to put a diagonal line over a textbox in CSS?