原文地址:Vertical-Align: All You Need To Know
Often I need to vertically align elements side by side.
我经常需要并排地垂直对齐元素。
CSS offers some possibilities. Sometimes I solve it with float, sometimes with position: absolute, sometimes even dirty by manually adding margins or paddings.
css提供一些解决方案。我有时使用float,有时使用position: absolute,有时甚至糟糕地手动添加margins或paddings来解决这个问题。
I don’t really like these solutions. Floats only align at their tops and need to be cleared manually. Absolute positioning takes the elements out of the flow so they do no longer affect their surroundings. And working with fixed margins and paddings immediately breaks things on the tiniest change.
我并不喜欢这些解决方案。Floats 只能对齐他们的tops,并且需要手动的清除浮动。绝对定位让元素脱离了流,因此它们再也不能影响周围的事物。使用固定的margins 和paddings会因为极细微的变化而打破。
But there is another player here: vertical-align. I think it deserves more credit. Ok, technically, using vertical-align for layout is a hack, since it wasn’t invented for this reason. It’s there to align text and elements next to text. Nonetheless, you can also use vertical-align in different contexts to align elements very flexible and fine-grained. The sizes of elements need not to be known. Elements stay in the flow so other elements can react to changed dimensions of those. This makes it a valuable option.
但是还有另一个解决方案在这儿:vertical-align。我认为它值得更多的青睐。技术上来说,使用vertical-align来布局是一种hack,因为它不是因为这个原因被发明的。它用来对齐文本和文本旁的元素。尽管如此,你也可以在不同的上下文中使用vertical-align灵活细致地对齐元素。元素的大小无需知道。元素呆在流中因此元素能够应对其他元素尺寸的改变。这也使得它成为一个有价值的选择。
Peculiarities Of Vertical-Align
But, vertical-align can be a real scumbag sometimes. Working with it can be a little frustrating. There seem to be some mysterious rules at work. For example, it might happen, that the element you changed vertical-align for doesn’t change its alignment at all, but other elements in the line do! I’m still getting dragged into the dark corners of vertical-align from time to time, tearing my hair.
但是,vertical-align有时真是一个卑鄙小人。使用它会让人有点沮丧。似乎有一些神秘的规则在起作用。例如,你为了不改变它的对齐而改变元素的vertical-align,但是其他在这一行的元素改变了。我仍然不时地被拖入vertical-align地黑暗角落,扯着我的头发。
Unfortunately, most resources on the matter are somewhat shallow. Especially, if we want to use vertical-align for layout. They concentrate on the misconception of trying to vertical align everything inside an element. They give basic introductions into the property and explain how elements are aligned in very simple situations. They do not explain the tricky parts.
不幸的是,大多数资源在这个事情上描述地都有点浅。尤其是,如果我们想要使用vertical-align去布局。他们专注于尝试垂直对齐一个元素内部一切的错误想法。他们对属性作基本介绍并且解释元素如何在简单的情况下被对齐。他们不解释复杂的那部分。
So, I set myself the target to clarify the behavior of vertical-align once and for all. I ended up working through the W3C’s CSS specifications and playing with some examples. The result is this article.
因此,我定下目标去彻底地理清vertical-align的行为。我最终通过W3C的CSS规范和玩一些例子结束这个事。这个结果就是这篇文章。
So, let’s tackle the rules of the game.
所以,让我们来解决游戏规则。
Requirements To Use Vertical-Align
vertical-align is used to align inline-level elements. These are elements, whose display property evaluates to
inline,
inline-block or
inline-table (not considered in this article).
Inline elements are basically tags wrapping text.
vertical-align用于对齐行内水平元素,即那些display属性为inline,inline-block或inline-table(本文不考虑)的元素。
行内元素基本上是包裹文本的标签。
Inline-block elements are what their name suggests: block elements living inline. They can have a width and height (possibly defined by its own content) as well as padding, a border and margin.
Inline-block元素就如他们的名字一样:块元素住着行内。它们可以有一个width 和height (可能由它自己的内容定义)以及padding、border 和margin。
Inline-level elements are laid out next to each other in lines. Once there are more elements than fit into the current line, a new line is created beneath it. All these lines have a so-called line box, which encloses all the content of its line. Differently sized content means line boxes of different height. In the following illustration the top and bottom of line boxes are indicated by red lines.
行内水平元素紧挨着行内其他元素放置。一旦当前行放不下所有的元素,会在该行下面产生新的行。所有这些行称之为line box,line box包含了这一行的所有内容。不同大小的内容意味着不同高度的line boxes。在下图中,line boxes的顶部和底部由红线表示。
The line boxes trace out the field we are playing on. Inside these line boxes the property vertical-align is responsible for aligning the individual elements. So, in respect to what are elements aligned?
line boxes勾画出我们可以玩的区域。在这些line boxes里面,属性vertical-align负责对齐各个元素。那么,关于元素对齐的那个呢?
About Baselines and Outer Edges
The most important reference point to align vertically is the baseline of the involved elements. In some cases the top and bottom edge of the element’s enclosing box becomes important, too. Let’s have a look where the baseline and outer edges live for each involved type of element:
垂直对齐最重要的参考点是所涉及元素的基线。在某些情况下,元素的包围盒的顶部和底部边缘也变得很重要。让我们看看每个涉及的元素类型的基线和外边缘的位置:
Here you see three lines of text next to each other. The top and bottom edge of the line height is indicated by red lines, the height of the font by green lines and the baseline by a blue line. On the left, the text has a line height set to the same height as the font-size. The green and red line collapsed to one line on each side. In the middle, the line height is twice as large as the font-size. On the right, the line height is half as large as the font-size.
在这里你可以看到文本相邻的三条线。行高的顶部和底部边缘由红线表示,字体的高度由绿线和基线由蓝色线表示。左侧的那个,文本的行高设置为与字体大小相同的高度。上下两边绿色和红色的线均重合为一条线。中间的那个,行高是字体高的两倍。右边的那个,行高是字体高的一半。
The inline element’s outer edges align themselves with the top and bottom edge of its line height. It does not matter, if the line height is smaller than the height of the font. So, the outer edges are the red lines in the figure above.
行内元素的外边缘与它的行高的顶部和底部边缘对齐。如果行高是小于字体高,也没有关系。所以,外边缘是上图中的红线。
The inline element’s baseline is the line, the characters are sitting on. This is the blue line in the figure. Roughly speaking, the baseline is somewhere below the middle of the font’s height. Have look at the W3C Specs for a detailed definition.
行内元素的基线是那条字符坐着的线。就是图中的蓝线。粗略地说,基线是在字体高度中间的下面的某个地方。看下W3C规范关于这个的详细的定义。
From left to right you see: an inline-block element with in-flow content (a “c”), an inline-block element with in-flow content and overflow: hidden and an inline-block element with no in-flow content (but the content area has a height). The boundaries of the margin is indicated by red lines, the border is yellow, the padding green and the content area blue. The baseline of each inline-block element is shown as a blue line.
从左到右你可以看到:一个inline-block元素里面有in-flow内容(一个“C”),一个inline-block元素有in-flow内容和overflow: hidden,一个inline-block元素没有in-flow内容(但是内容区域有高度)。margin的边界由红线表示,border为黄色,padding为绿色和内容区域为蓝色。每个inline-block元素的基线是蓝色线。
【译注】:如果一个元素是浮动的(float:left/right),绝对定位的(position:absolute/fixed)或者是根元素(html),那么它被称之为流外的元素(out-of-flow)。如果一个元素不是流外的元素,那么它被称之为流内的元素(in-flow)。
The Inline-block element’s outer edges are the top and bottom edge of its margin-box. These are the red lines in the figure.
Inline-block元素的外边缘是它的margin-box的顶部和底部边缘。就是图中的红线。
The Inline-block element’s baseline depends on whether the element has in-flow content:
In case of in-flow content the baseline of the inline-block element is the baseline of the last content element in normal flow (example on the left). For this last element its baseline is found according to its own rules.
In case of in-flow content but an overflow property evaluating to something other than visible, the baseline is the bottom edge of the margin-box (example in the middle). So, it is the same as the inline-block element’s bottom edge.
In case of no in-flow content the baseline is, again, the bottom edge of the margin-box (example on the right).
Inline-block元素的基线取决于元素是否具有in-flow内容:
有in-flow内容,inline-block元素的基线是普通流中最后一个内容元素的基线(例如左边那个)。对于最后一个元素,它的基线是根据它自己的规则确定位置的。
有in-flow内容并且使用了值不是visible的overflow,基线就在margin-box的底部边缘那个位置(例如中间那个)。因此,它与inline-block元素的底部边缘一样。
没有in-flow内容,基线也是在margin-box的底部边缘那个位置(例如右边那个)
You’ve already seen this setting above. This time I drew in the top and bottom of the line box’s text box (green, more on this below) and the baseline (blue), too. I also highlighted the area of the text elements by giving them a grey background.
你已经看到以上设置。这一次我画line box的文本盒(绿色,远在这下面)的顶部和底部和基线(蓝色)。我还通过给他们一个灰色背景来强调文本元素的区域。
The line box has a top edge aligned to the top edge of the top-most element of this line and a bottom edge aligned to the bottom edge of the bottom-most element of the line. This is the box indicated by the red lines in the figure above.
line box的顶部边缘与该行内最高元素的顶部边缘对齐,line box的底部边缘与该行内最底元素的底部边缘对齐。line box就是上图中红线标出的那部分。
The line box’s baseline is variable:
CSS 2.1 does not define the position of the line box‘s baseline. — the W3C Specs
line box的基线是变量:
CSS 2.1 不定义line box基线的位置。-W3C 规范
This is probably the most confusing part, when working with vertical-align. It means, the baseline is placed where ever it needs to be to fulfil all other conditions like vertical-align and minimizing the line box’s height. It is a free parameter in the equation.
这可能是最让人困惑的一部分。这意味着,基线被放在能够实现所有条件(像vertical-align,最小化line box的高度)的地方。它是方程中的一个自由参数。
Since the line box’s baseline is invisible, it may not immediately be obvious where it is. But, you can make it visible very easily. Just add a character at the beginning of the line in questions, like I added an “x” in the figure. If this character is not aligned in any way, it will sit on the baseline by default.
因为line box的基线是不可见的,所以它所在的地方是不明显的。但是,你可以让它很容易被看到。仅需要在行的开头增加一个字符,就像我在图中增加的“X”。如果这个字符没有以任何方式对齐,它将默认地坐在基线上。
Around its baseline the line box has what we might call its text box. The text box can simply be thought of as an inline element inside the line box without any alignment. Its height is equal to the font-size of its parent element. Therefore, the text box only just encloses the unformatted text of the line box. The box is indicated by the green lines in the figures above. Since this text box is tied to the baseline, it moves when the baseline moves. (Side note: this text box is called strut in the W3C Specs)
在它的基线周围,line box有文本盒。文本盒可以当做是放在line box里面的没有任何对齐的行内元素。它的高度等于它的父元素的字体大小。因此,文本盒只是把line box的无格式文本围起来了。这个盒子就是上图中用绿线标出来的那个。因为这个文本盒与基线相关联,当基线移动时,它也移动。(注:这个文本盒在W3C规范中称为strut)
Phew, this was the hard part. Now, we know everything to put things into perspective. Let’s quickly sum up the most important facts:
There is an area called line box. This is the area in which vertical alignment takes place. It has a baseline, a text box and a top and bottom edge.
There are inline-level elements. These are the objects that are aligned. They have a baseline and a top and bottom edge.
唉,这是最难的部分。现在,我们知道一切。让我们快速总结出最重要的事实:
有一个叫做line box的区域。这是垂直对齐发生的区域。它有一条基线,一个文本盒和一个顶部和底部边缘。
有行内水平元素。他们是要对齐的对象。他们有一条基线和一个顶部和底部边缘。
The Values Of Vertical-Align
By using vertical-align the reference points mentioned in the last sentence in the list above are set into a certain relationship.
通过使用vertical-align,上面列表中最后一句中提到的参考点被设置成一定的关系。
Aligning the Element’s Baseline Relative To the Line Box’s Baseline
baseline: The element’s baseline sits exactly on top of the line box’s baseline.
sub: The element’s baseline is shifted below the line box’s baseline.
super: The element’s baseline is shifted above the line box’s baseline.
<percentage>: The element’s baseline is shifted with respect to the line box’s baseline by a percentage relative to the line-height.
<length>: The element’s baseline is shifted with respect to the line box’s baseline by an absolute length.
将元素基线相对于line box的基线对齐。
baseline:元素的基线在line box的基线顶部。
sub:元素的基线移动到line box基线以下。
<percentage>:元素的基线通过与line-height相关联的percentage ,相对于line box的基线进行偏移。
<length>:元素的基线通过绝对长度相对于line box的基线进行偏移
Aligning the Element’s Outer Edges Relative To the Line Box’s Baseline
middle: The midpoint between the element’s top and bottom edge is aligned to the line box’s baseline plus half of the x-height.
将元素外边缘相对于line box的基线对齐。
middle:元素顶部和底部两者间的中点与line box的基线加上二分之一的x-height对齐。
Aligning the Element’s Outer Edges Relative To the Line Box’s Text Box
One could also list these two cases under aligning relative to the line box’s baseline, since the position of the text box is determined by the baseline.
text-top: The element’s top edge is aligned to the line box’s text box top edge.
text-bottom: The element’s bottom edge is aligned to the line box’s text box bottom edge.
将元素外边缘相对于line box的文本盒对齐。
也可以将这两种情况列在“相对于line box的基线对齐”下,因为文本盒的位置是由line box的基线决定的
。
text-top:元素的顶部边缘与line box的文本盒的顶部边缘对齐。
text-bottom:元素的底部边缘与line box的文本盒的底部边缘对齐。
Aligning the Element’s Outer Edges Relative To the Line Box’s Outer Edges
top: The element’s top edge is aligned to the line box’s top edge.
bottom: The element’s bottom edge is aligned to the line box’s bottom edge.
将元素外边缘相对于line box的外边缘对齐
top: 元素的顶部边缘与line box的顶部边缘对齐。
bottom:元素的底部边缘与line box的底部边缘对齐。
The formal definition is found in, of course, the W3C Specs.
正式定义在W3C规范的这里。
Why Vertical-Align Behaves The Way It Behaves
We can now take a closer look at vertical alignment in certain situations. Especially, we will deal with situations where things might have gone wrong.
我们现在可以仔细看看在某些情况下地垂直对齐。主要地,我们将处理那些我们可能已经错了的情况。
Centering an Icon
One question bugging me was the following: I have an icon I want to center next to a line of text. Just giving the icon a vertical-align: middle didn’t seem to center it in a satisfying way. Have a look at this example:
一个问题困扰着我:我有一个图标,我想将图标中心和紧挨着的文本的中心对齐。仅仅给图标一个vertical-align: middle似乎并不能以满意的方式居中。看下这个例子:
<!-- left mark-up -->
<span class="icon middle"></span>
Centered?
<!-- right mark-up -->
<span class="icon middle"></span>
<span class="middle">Centered!</span>
<style type="text/css">
.icon { display: inline-block;
/* size, color, etc. */ }
.middle { vertical-align: middle; }
</style>
Here is the example again, but I drew in some auxiliary lines you already know from above:
仍是这个例子,但是我画了一些辅助线。
This sheds some light on our matter. Because the text on the left isn’t aligned at all, it sits on the baseline. The thing is, by aligning the box with vertical-align: middle we are aligning it to the middle of the lower case letters without ascenders (half of the x-height). So, characters with ascenders stand out at the top.
这揭示了我们的问题。因为左边的文本没有对齐,它位于基线上。事实是,通过vertical-align: middle对齐时,我们将它和小写字母的中间对齐,并没有和ascenders对齐(x-height的一半)。因此,字符和ascenders 站在顶部。
On the right, we take the whole area of the font and align its midpoint vertically, too. The text’s baseline shifts slightly below the line box’s baseline to achieve this. The Result is a nicely centered text next to an icon.
在右边,我们把字体的整个区域中点垂直置中。文本的基线轻轻地移到了line box的基线下面来达成这个目的。这个结果是文本完美的和图标中心对齐。
Movement Of the Line Box’s Baseline
This is a common pitfall when working with vertical-align: The position of the line box’s baseline is affected by all elements in that line. Let’s assume, an element is aligned in such a way, that the baseline of the line box has to move. Since most vertical alignment (except top and bottom) is done relative to this baseline, this results in an adjusted position of all other elements in that line, too.
当使用这个时,这是一个常见的陷阱:line box的基线的位置受该行所有元素的影响。让我们假设,一个元素以这样的方式对齐,即line box的基线必须移动。由于大多数垂直对齐(除了top和bottom)是相对于这个基线,这导致在该行的所有其他元素调整位置。
Some Examples:
If there is a tall element in the line spanning across the complete height, vertical-align has no effect on it. There is no space above its top and below its bottom, that would let it move. To fulfil its alignment relative to the line box’s baseline, the line box’s baseline has to move. The short box has a vertical-align: baseline. On the left, the tall box is aligned text-bottom. On the right, it is aligned text-top. You can see the baseline jumping up taking the short box with it.
一些例子:
如果有一个高大的元素跨越整个高度线,vertical-alig对它就没有影响。在它的上面和下方没有让它移动的空间。为了实现相对于line box基线的对齐,line box的基线必须移动。短框的vertical-align: baseline。左边的那个,高大的元素和text-bottom对齐。右边的那个,高大的元素和text-top对齐。你可以看到基线带着短框一起跳跃。
<!-- 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>
The same behaviour shows up when aligning a tall element with other values for vertical-align.
当高个的元素用vertical-align的其他值去对齐时,是相同的行为。
Even setting vertical-align to bottom (left) and top (right) moves the baseline. This is strange, since the baseline shouldn’t be involved 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>
甚至设置vertical-align为bottom(left)和top(right)也会移动基线。这是奇怪的,因为基线不应该涉及所有。
Placing two larger elements in a line and vertically aligning them moves the baseline where it fulfils both alignments. Then the height of the line box is adjusted (left). Adding a third element, that does not go beyond the line box’s edges because of its alignment, affects neither the line box’s height nor the baseline’s position (middle). If it does go beyond the line box’s edges, the line box’s height and baseline are adjusted, again. In this case, our first two boxes are pushed down (right).
<!-- left mark-up -->
<span class="tall-box text-bottom"></span>
<span class="tall-box text-top"></span>
<!-- mark-up in the middle -->
<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>
将两个大点的元素放在一行,然后垂直对齐他们使基线在符合这两个元素对齐方式的地方。line box的高会调整(左)。增加第三个元素,它不超出line box的边缘,因为它的对齐方式,既不影响line box的高度也不影响基线的位置(中)。如果他超出了line box的边缘,line box的高和基线会再次调整。在这种情况下,我们的前两个箱子被推下来了(右)。
There Might Be a Little Gap Below Inline-Level Elements
Have a look at this setting. It’s common if you try to vertical-align li elements of a list.
<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>
看看这个设置。这是常见的,如果你试图垂直对齐列表中的li元素。
As you can see, the list items sit on the baseline. Below the baseline is some space to shelter the descenders of a text. This is causing the gap. The Solution? Just move the baseline out of the way, for example by aligning the list items with 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>
正如您所看到的,列表项位于基线上。在基线下是放文本的descenders 空间。这造成了缝隙。解决的方法呢?仅需要移动基线的位置,例如将列表项设置为vertical-align: middle。
This scenario does not occur for inline-blocks having text content, since content already moves the baseline up.
对于已经有内容的inline-blocks不会发生该场景,因为内容已经将基线移上去了。
A Gap Between Inline-Level Elements Is Breaking the Layout
This is mainly a problem of inline-level elements themselves. But since they are a requirement of vertical-align, it is good to know about this.
这是行内水平元素的一个主要问题。但是因为他们是vertical-align的必备条件,所以最好知道这个。
You can see this gap in the former example between the list items. The gap comes from the white-space between inline-elements present in your mark-up. All white-space between inline-elements is collapsed into one space. This space gets in the way, if we want to place two inline elements next to each other and giving them width: 50%, for example. There is not enough space for two 50%-elements and a space. So the line breaks into two lines destroying the layout (left). To remove the gap, we need to remove the white-space, for example with html comments (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>
你可以看到在前面的例子中在列表项之间的间隙。间隙来自标记中存在的行内元素之间的空白。行内元素之间的所有空白被折叠成一个空格。如果我们想将两个行内元素放在一起,并都给它们50%的宽度,这个空格会碍事。没有足够的空间放两个50%宽的元素和一个空格。因此这一行就会破坏原有的布局变成两行(左)。为了去掉间隙,我们需要去掉空白,例如使用html注释(右)。
Vertical-Align Demystified
Yea, that’s it. It is not very complicated once you know the rules. If vertical-align does not behave, just ask these questions:
Where is the baseline and top and bottom edge of the line box?
Where is the baseline and top and bottom edge of the inline-level elements?
This will corner the solution to the problem.
是的,就是这样。一旦你知道了规则,就不是很复杂了。如果vertical-align表现不对,就问下这些问题:
基线,line box的顶部和底部边缘在哪里?
基线,行内水平元素的顶部和底部边缘在哪里?
这将解决那个问题。
以上翻译如有不当之处,请指正!