原文地址:Vertical-Align: All You Need To Knowcss
Often I need to vertically align elements side by side.html
我常常須要並排地垂直對齊元素。react
CSS offers some possibilities. Sometimes I solve it with float, sometimes with position: absolute, sometimes even dirty by manually adding margins or paddings.app
css提供一些解決方案。我有時使用float,有時使用position: absolute,有時甚至糟糕地手動添加margins或paddings來解決這個問題。less
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.ide
我並不喜歡這些解決方案。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靈活細緻地對齊元素。元素的大小無需知道。元素呆在流中所以元素可以應對其餘元素尺寸的改變。這也使得它成爲一個有價值的選擇。flex
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.ui
可是,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.
因此,讓咱們來解決遊戲規則。
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負責對齊各個元素。那麼,關於元素對齊的那個呢?
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的區域。這是垂直對齊發生的區域。它有一條基線,一個文本盒和一個頂部和底部邊緣。
有行內水平元素。他們是要對齊的對象。他們有一條基線和一個頂部和底部邊緣。
By using vertical-align the reference points mentioned in the last sentence in the list above are set into a certain relationship.
經過使用vertical-align,上面列表中最後一句中提到的參考點被設置成必定的關係。
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的基線進行偏移
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對齊。
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的文本盒的底部邊緣對齊。
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規範的這裏。
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.
咱們如今能夠仔細看看在某些狀況下地垂直對齊。主要地,咱們將處理那些咱們可能已經錯了的狀況。
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的基線下面來達成這個目的。這個結果是文本完美的和圖標中心對齊。
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的高和基線會再次調整。在這種狀況下,咱們的前兩個箱子被推下來了(右)。
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不會發生該場景,由於內容已經將基線移上去了。
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註釋(右)。
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的頂部和底部邊緣在哪裏?
基線,行內水平元素的頂部和底部邊緣在哪裏?
這將解決那個問題。
以上翻譯若有不當之處,請指正!