Ok, let’s talk about vertical-align. The main purpose of this attribute is to align adjacent text with elements. In fact, Verticle-Algin allows flexible alignment of elements in different contexts and fine-grained control without knowing the size of the elements. The element is still in the document flow, so other elements can be adjusted as their size changes. A useful example is the center icon with text next to it.

Vertical-align is a monster

Vertical-align, however, can be difficult and often leads to confusion. As if there were some mysterious rule at work. For example, if we change the vertical-align of an element and its alignment does not change, the alignment of other elements in the same row changes! I still fall into the vertical-align pit every now and then, desperate.

Unfortunately, much of the information on this subject is superficial. Especially in the case of layout. Many articles misconceptually try to align everything in an element vertically. They introduce the basic concepts of this attribute and explain the alignment of elements in simple cases, but leave out the really tricky part.

So I set myself a goal: to understand vertical-align’s behavior once and for all. Then I devoured the W3C’s CSS specification and tried out some examples. I ended up writing this article.

Ok, so let’s get started.

For which elements you can use vertical-align

Vertical-align aligns elements in a row. An inline element is an element whose display attribute is one of the following:

  • inline
  • inline-block
  • inline-table(Not covered in this article)

An inline element is a label that contains text.

An inline-block element, as the name suggests, is a block element located inside a row. It can have a width and height (which can be determined by its content), as well as inside margins, borders, and margins.

The in-line elements are placed next to each other in a row. If a row does not fit, a new row is created below. All rows create what are called row boxes, which hold all the content in their row. The height of the line box is different depending on the height of the content. In the diagram below, the top and bottom of the row boxes are indicated by red dotted lines.

These boxes define what we can influence. Inside the row box, you can align individual elements with vertical-align. So, how do you align elements with respect to what?

Baseline and outer boundary

The most important reference point for vertical alignment is the relevant element baseline. In some cases, the upper and lower outer boundaries of a row box also serve as reference points. Let’s take a look at the baseline and outer bounds of the related element types.

Inline elements

There are three lines of text right next to each other. The red line represents the top and bottom of the line height, the green line represents the font height, and the blue line represents the baseline. On the left side, the line height is the same as the font height, so the red and green lines above and below overlap. The middle line is twice as tall as the font size. The right row is half the height of font size.

The outer boundary of the inline element is aligned above and below its own row height. It doesn’t matter if the line height is smaller than font size. So the red line in the figure above is also the outer boundary.

The baseline for inline elements is the line on which the character is located, the blue line in the figure. Roughly speaking, the baseline always passes through some point less than half the height of the font. Refer to the W3C specification for detailed definitions.

Inline block elements

From left to right: inline blocks that contain in-stream content (” C “), inline blocks that contain in-stream content with overflow: hidden, and inline blocks that do not contain in-stream content (but have height in the content area). The red line represents the border of the margin, the yellow is the border, the green inner margin, the blue is the content area, and the blue line is the baseline of each inline block element.

The outer boundary of the inline block element is the upper and lower sides of the outer box, which is the red line in the figure.

The baseline for inline block elements depends on whether the element contains in-stream content:

  • For inline block elements with in-stream content, the baseline is the baseline of the last content element in a normal stream (left). The baseline for this last element is found according to its own rules.
  • There are streaming contents butoverflowProperty value is notvisibleThe line block element, whose baseline is the bottom edge of the margin box (middle). That is, it coincides with the lower outer boundary of the inline block element.
  • For inline block elements with no in-stream content, the baseline is again the bottom edge of the margin box (right).

Line box

I’ve seen this before. But this time we drew the text of the row box above and below the box (green, more on that below) and the baseline (blue). At the same time, a gray background is used to represent the area of text elements.

The top edge of the row box coincides with the top edge of the topmost element in the row, and the bottom edge coincides with the bottom element in the row. So the red lines are row boxes.

The baseline of a row box is a variable:

CSS 2.1 does not define a baseline for row boxes.


The W3C specification

This is probably the most confusing area when using vertical-align. In other words, there are a number of conditions that need to be met, such as vertical-align and the minimum height of the box. This is a free variable.

Because the baseline of a row box is not visible, it is sometimes not easy to determine its position. But there’s actually an easy way to make it visible. Simply add a letter to the beginning of the relevant line, such as the “X” shown above. If the letter is not aligned, it defaults to above the baseline.

Surrounding the baseline is the text box in the line box. You can simply think of a text box as an unaligned inline element inside a line box. The height of the text box is equal to the font size of its parent element. Therefore, text boxes are only used to hold unformatted text. The green line in the figure above is the text box. Because the text box is associated with the baseline, it moves with the baseline. (The W3C specification calls this text box a strut.)

I finally got the hard part over with. Now we know everything about alignment. Here’s a quick summary of the two most important points.

  • There is an area called the row box. The contents of a row box can be aligned vertically. Line boxes have baselines, text boxes, and top and bottom.
  • There are inline elements, which are objects that can be aligned. Inline elements have baselines, and top and bottom elements.

The value of Vertical – Align

With vertical-align, the reference points mentioned earlier are set up in a certain relationship.

Align the baseline of the inline element with the baseline of the row box

  • baseline: Element baseline coincides with row box baseline.
  • sub: Element baseline moves below row box baseline.
  • super: Element baseline moves above row box baseline.
  • < percentage value >: The element baseline moves up or down relative to the row box baseline by a distance equal toline-heightPercentage of.
  • < length value > : The element baseline moves up or down a specified distance relative to the row box baseline.

Aligns the outer boundary of the element with respect to the baseline of the row box

  • middle: The midpoints on and below the element are half aligned with the line box baseline plus x-height.

The text box relative to the line box aligns the outer boundary of the element

There are also two cases where the alignment is relative to the baseline of the line box, because the position of the text box is determined by the baseline of the line box.

  • text-top: The top edge of the element is aligned with the top edge of the text box of the line box.
  • text-bottom: The bottom edge of the element is aligned with the bottom edge of the text box of the line box.

Aligns the outer boundary of the element with respect to the outer boundary of the row box

  • top: The top edge of the element is aligned with the top edge of the row box.
  • bottom: The bottom edge of the element is aligned with the bottom edge of the row box.

Of course, the formal definition is in the W3C specification.

Why is Vertical-Align behaving so strangely

Let’s look at vertical alignment in some cases. Especially something that can go wrong.

Center icon

There’s a question that’s been bothering me. There is an icon that I want to center vertically with a line of text. If only vertical-align: middle is applied, it will not work, as in this example:

<span class="icon middle"></span> Centered? <span class="icon middle"></span> <span>Centered! </span> <style type="text/css"> .icon { display: inline-block; /* size, color, etc. */ } .middle { vertical-align: middle; } </style>Copy the code

It’s the same example, but with a few more guides:

This time you can see the problem. This is because the text on the left is not aligned and is still above the baseline. Applying vertical-align: middle actually causes the center of the icon to align with the center of the lower-case letter (half of x-height), so that the leading letter stands out above it.

On the right, the vertical midpoint is still aligned with the entire font area. As a result, the text baseline moves down a bit, so that the text aligns perfectly with the icon.

Line box baseline movement

This is a common pitfall when using vertical-align: the position of the baseline of a row box is affected by all of its elements. Assume that the alignment of an element causes the row box to move. Since most vertical alignments (except top and bottom) are computed relative to the baseline, this causes all other elements in the line to be repositioned.

Here are a few examples.

  • If you have a tall element in a row that has no space above or below it, you have to move it to align with the baseline of the row box. The short box is vertical-align: baseline. The left side of the box is vertical-align with the text-bottom, and the right side is vertical-algin with the text-top. As you can see, the baseline moves up with the low box.

    <! -- left mark-up --> <span class="tall-box text-bottom"></span> <span class="short-box"></span> <! -- right mark-up --> <span class="tall-box text-top"></span> <span class="short-box"></span> <style type="text/css"> .tall-box, .short-box { display: inline-block; /* size, color, etc. */ } .text-bottom { vertical-align: text-bottom; } .text-top { vertical-align: text-top; } </style>Copy the code

    The same happens when a higher element is aligned with the other values of vertical-align.

  • Even setting vertical-align to bottom (left) and top (right) will cause the baseline to move. And that’s weird, because it’s not about the baseline at all.

    <! -- left mark-up --> <span class="tall-box bottom"></span> <span class="short-box"></span> <! -- right mark-up --> <span class="tall-box top"></span> <span class="short-box"></span> <style type="text/css"> .tall-box, .short-box { display: inline-block; /* size, color, etc. */ } .bottom { vertical-align: bottom; } .top { vertical-align: top; } </style>Copy the code
  • Place the two larger elements on a line and align them vertically, and the baseline moves to match both alignments. The height of the row is then adjusted (left). Add one more element, but the alignment of the element determines that it does not exceed the boundaries of the row box, so the row box does not adjust (middle). If the new element goes beyond the boundary of the row box, the height and baseline of the row box are adjusted again. In this example, the first two boxes are moved down (right).

    <! -- left mark-up --> <span class="tall-box text-bottom"></span> <span class="tall-box text-top"></span> <! -- middle mark-up --> <span class="tall-box text-bottom"></span> <span class="tall-box text-top"></span> <span class="tall-box middle"></span> <! -- right mark-up --> <span class="tall-box text-bottom"></span> <span class="tall-box text-top"></span> <span class="tall-box text-100up"></span> <style type="text/css"> .tall-box { display: inline-block; /* size, color, etc. */ } .middle { vertical-align: middle; } .text-top { vertical-align: text-top; } .text-bottom { vertical-align: text-bottom; } .text-100up { vertical-align: 100%; } </style>Copy the code

There may be a small gap below the inline elements

Consider this example: apply vertical-align to the li of a list element.

<ul>
  <li class="box"></li>
  <li class="box"></li>
  <li class="box"></li>
</ul>

<style type="text/css">
  .box { display: inline-block;
         /* size, color, etc. */ }
</style>
Copy the code

We see that the list items are at the baseline. There is a small gap below the baseline for the drop down portion of the text. How to do? Just move the baseline up a little bit, like vertical-align: middle.

<ul>
  <li class="box middle"></li>
  <li class="box middle"></li>
  <li class="box middle"></li>
</ul>

<style type="text/css">
  .box    { display: inline-block;
            /* size, color, etc. */ }

  .middle { vertical-align: middle; }
</style>
Copy the code

This does not happen with inline blocks with text content because the content has moved the baseline up.

Gaps between elements in a row can ruin the layout

This is mostly a problem with the inline elements themselves. Since vertical-align inevitably encounters inline elements, it’s worth knowing.

You can also see this gap in the previous list item example. This gap comes from the white space between the inline elements in your tag. All the white space between the elements in the line collapses into one. If we were to implement and exhaust two inline elements with width: 50%, this white space would be an obstacle. Because there is no room for two 50%’s plus a blank line, the result is folded (left). To remove this gap, you need to comment out the white space in your HTML (right).

<! -- left mark-up --> <div class="half">50% wide</div> <div class="half">50% wide... and in next line</div> <! -- right mark-up --> <div class="half">50% wide</div><! -- --><div class="half">50% wide</div> <style type="text/css"> .half { display: inline-block; width: 50%; } </style>Copy the code

The Vertical – Align revelation

Ok, that’s all. Once you know the rules, it’s not that complicated. If vertical-align isn’t working, just ask the following questions to find the problem:

  • Where are the baseline and upper and lower boundaries of a row box?
  • Where are the baseline and upper and lower boundaries for inline elements?

From this, a solution to the problem can be found.