转载

Vertical-Align: 你需要知道的所有事【译】

Vertical-Align: 你需要知道的所有事

原文地址: Vertical-Align: All You Need To Know

我经常需要垂直对齐元素。

CSS提供了一些可能的方法。有时我用 float 解决它,或使用 position: absolute; ,还有时甚至要恶心地手动添加 marginpadding

我不是真的喜欢这些解决方案。 float 只能对准在其顶部而且需要手动清除。绝对定位将元素从文档流中抽离出来,这样它们就不再能撑开(影响)其包含块。使用固定的 marginpadding 则很容易被微小的变化所破坏。

但这里有另一个方法: vertical-align ,我认为它值得得到更多的信赖。从技术上讲,使用 vertical-align 布局是一种hack方式,因为它不是为这个原因发明的。它的存在是为了对齐文本和文本旁的元素。尽管如此,你也可以在不同的上下文中使用 vertical-align 来非常灵活和精准地对齐元素。优点是元素的大小不需要知道,且留在文档流中,所以其他元素(包含块)可以响应布局尺寸的改变,这使它成为一个有价值的选择。

vertical-align的独特性

但是, vertical-align 有时会相当卑鄙,并使你感到沮丧。在工作中似乎有一些神秘的规则,例如,这种情况经常发生,被改变了 vertical-align 的元素并没有改变它的对齐方式,但同一行的其他元素却改变了!我有时仍然被 vertical-align 拖到黑暗的角落并撕扯头发。

不幸的是,大部分关于这个的教程都有点浅,特别是如果我们要使用 vertical-align 来布局。大多数人专注于尝试垂直对齐元素的一些误解,他们给出基本的介绍,并解释在非常简单的情况下如何对齐元素,但没有解释棘手的部分。

所以,我给自己定了个目标: 彻底弄清楚 vertical-align 的行为 ,不留下历史问题。我最终通过W3C的 CSS 规范 和试验一些例子得到了结果——这篇文章。

使用vertical-align的要求

vertical-align 用来调整 inline 级元素。这些元素的 display 属性为:

  • inline
  • inline-block
  • inline-table(本文不涉及)

inline元素基本上是文本的包裹标签。

inline-block元素正如它们的名字:住在行内的块元素。他们可以有一个width和height(也可能由它内部内容撑开),以及padding、border和margin。

inline元素逐个从左到右地被放置在一行内。一旦有更多的元素加入,使当前行无法放下,一个新的行就会在下方产生。所有这些行有所谓的 line box ,其中包含所有的内容。不同尺寸的内容意味着不同高度的line box。在下图中,line box的顶部和底部是红色线表示的:

Vertical-Align: 你需要知道的所有事【译】

line box描绘出了我正在试验的区域。在这些line box中,属性 vertical-align 是负责调整单个元素的。 所以,元素对齐跟什么相关?

关于baseline和外边缘

垂直对齐最重要的关注点是要对其元素的baseline。在某些情况下,元素的包围盒的顶部和底部的边缘也变得很重要。让我们来看看每种类型的元素baseline和外边缘在哪里:

inline元素

Vertical-Align: 你需要知道的所有事【译】

在这里你看到三行的文本相邻排布。行高的顶部和底部是由红线表示的,字体的高度是由绿线来表示的,而baseline是由蓝线表示的。在左边,文本具有一个与字体大小相同的行高,绿色和红线在上下都重叠了。在中间,行高(line-height)是字体大小的两倍大。在右边,行高是字体大小(font-size)的一半。

inline元素的外边缘跟自己line-height的顶部和底部边缘对齐,如果line-height小于font-size的话也不会改变。所以,在上面的图中的行的外边界是红线。

inline元素的baseline字符底部所坐的线,就是图中的蓝线。粗略地说,baseline是在font-size中间下面的一个地方,看看W3C规范的 详细定义 。

inline-block元素

Vertical-Align: 你需要知道的所有事【译】

从左到右,你看到的是一个拥有 流 内容(一个“c”)的inline-block元素,一个拥有流内容且 overflow: hidden; 的inline-block元素和一个没有流内容的inline-block元素(但内容区域有一个高度)。margin的边界由红线表示,以及黄色的border,绿色的padding和蓝色的内容区域,蓝线是每个inline-block元素的baseline。

inline-block元素的外边缘是其 margin-box 的顶部和底部边缘,即图中的红线。

inline-block的baseline取决于元素是否具有流内容:

  • 在流内容的情况下,inline-block元素的baseline是正常流的最后一个内容元素的baseline(左边的例子)。对于这最后一个元素,它的baseline位置由它自己的规则决定。
  • 在流内容,但具有overflow:hidden的情况下,baseline是margin-box的底边缘(中间的例子),也相当于inline-block元素的底边缘。
  • 如果没有流内容,则跟上一个一样,baseline位于margin-box的底边缘(右边的例子)。

line box

Vertical-Align: 你需要知道的所有事【译】

你已经看过了这张图上面的设置,这一次,我画出了line box的text box的顶部和底部边缘(绿线,下文也是)以及baseline(蓝线)。我还给该区域的文本元素添加了一个灰色的背景来强调他们。

该line box具有一个与该行最顶的元素的顶部边缘对齐的 顶部边缘 和一个与该行最底的元素的底部边缘对齐的 底部边缘 ,即是上面图中的红色线所表示的盒子。

line box的baseline是可变的:

CSS 2.1并没有定义line box的baseline. —- W3C规范

这可能是使用vertical-align时最令人困惑的部分。意思是,baseline的位置要在满足所有其他条件,如vertical-align设置和最小化line box的高度的前提下来决定,是方程中的一个自由参数。

由于line box的baseline是不可见的,无法直观感知。但是,你可以很容易地让它变得可见。通过在行的开头加一个字符,比如上图中的字母“×”。如果这个字符没有以任何方式进行对齐,则默认情况下其底部将坐在baseline上。

在其baseline的基础上,line box有一个称为 text box 的东西。该text box可以简单地被认为是line box中一个没有任何对齐的inlne元素。它的高度等于它的父元素的font-size。因此,text box只包裹住line box中的无格式文本,由上图中的绿线表示。因为这个text box位置基于baseline,所以它会随baseline移动。(注:此text box在W3C规范中称为 strut

唉,这是最难的部分。现在,我们拥有了分析原理的所有前提条件,让我们迅速总结最重要的事实:

  • 有一个区域称为 line box ,这是要对齐的区域。它有一个 baseline ,一个 text box 和一个 顶部底部边缘
  • inline级元素 。这些是要被对齐的对象。他们有一个 baseline 和一个 顶部底部边缘

vertical-align的取值

从上面的列表总结出来的使用 vertical-align 的要点中,我设置了几种关系样例。

将元素的baseline与line box的baseline对齐

Vertical-Align: 你需要知道的所有事【译】

  • baseline:该元素的baseline恰好与line box的baseline重合。
  • sub:该元素的baseline偏移到line box的baseline下方。
  • super:该元素的baseline偏移到line box的baseline上方。
  • <百分比>:该元素的baseline以line-height高度乘以百分比的距离相对于line box的baseline偏移。
  • <长度>:该元素的baseline以绝对长度相对于line box的baseline偏移。

将元素的外边缘与line box的baseline对齐

Vertical-Align: 你需要知道的所有事【译】

  • middle:元素的顶部和底部边缘的中点与line box的baseline加上1/2小写字母x高度的位置对齐。

将元素的外边缘与line box的text box对齐

Vertical-Align: 你需要知道的所有事【译】

这2种情况也可以以相对于line box的baseline对齐的方式展现出来,因为text box的位置是由baseline确定的。

  • text-top:该元素的顶部边缘与line box的text box顶部边缘对齐。
  • text-bottom:该元素的底部边缘与line box的text box的底部边缘对齐。

将元素的外边缘与line box的外边缘对齐

Vertical-Align: 你需要知道的所有事【译】

  • top:元素的顶部边缘与line box的顶部边缘对齐。
  • bottom:该元素的底部边缘与line box的底部边缘对齐。

正式的定义 可以在W3C规范中找到。

为什么vertical-align以这种规则表现

我们现在可以在特定情况下来研究一下垂直对齐,特别是有可能会出错的情况。

居中一个图标

下面这个问题曾经烦扰了我:我想把图标与旁边的一行文本垂直居中对齐,只是给图标设置 vertical-align: middle; 似乎并没有如设想的一样居中。看看底下这个例子:

Vertical-Align: 你需要知道的所有事【译】
<!-- left mark-up --> <spanclass="icon middle"></span> Centered?   <!-- right mark-up --> <spanclass="icon middle"></span> <spanclass="middle">Centered!</span>   <styletype="text/css">   .icon  { display: inline-block;             /* size, color, etc. */ }     .middle{ vertical-align: middle; } </style> 

下面的图还是上面的例子,但我画了一些之前提到过的辅助线:

Vertical-Align: 你需要知道的所有事【译】

这揭示了我们的问题。左边的x和Centered?没有设置对齐属性,所以它坐在baseline上。重要的是,用 vertical-align: middle; 对齐灰色方块(即图标)后,我们把它的中点与line box的baseline加上x高度的一半处对齐了(图中黄线),然而由于Centered?中部并不在黄线上,所以就显得高于灰色方块(图标)。

在右边,我们进一步把文字中点也对齐了,这使得文本的baseline略微往line box的baseline下方偏移了一点。最终得到了完美的结果。

line box baseline的移动

这里有一个使用 vertical-align 常见的盲点:line box baseline的位置会被行内所有元素所影响。让我们假设这种情况,一个元素以使得line box baseline必须移动的方式进行对齐。由于大多数垂直对齐方式(除了顶部和底部)与baseline相关,这会导致该行中的所有其他元素移动。

一些例子:

  • 如果有一个很高的元素占据了整行的高度,事实上它也决定了整行高度,那么 vertical-align 对它就没有效果,上下都没有空间让它移动,所以line box的baseline为了满足对齐关系必须移动。在下图中,短方块设置了 vertical-align: baseline; ,左例中高方块的垂直对齐方式是 text-bottom ,而在右边中是 text-top 。你可以看到baseline与短方块始终在一起。

Vertical-Align: 你需要知道的所有事【译】

<!-- left mark-up --> <spanclass="tall-box text-bottom"></span> <spanclass="short-box"></span>   <!-- right mark-up --> <spanclass="tall-box text-top"></span> <spanclass="short-box"></span> <styletype="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> 

当用 vertical-align 的其他值来对齐高方块时也有相似的表现。

  • 然而甚至设置 vertical-alignbottom (左图)和 top (右图)也会使baseline移动。这十分奇怪,因为这应该与baseline并无关系。

Vertical-Align: 你需要知道的所有事【译】

<!-- left mark-up --> <spanclass="tall-box bottom"></span> <spanclass="short-box"></span>   <!-- right mark-up --> <spanclass="tall-box top"></span> <spanclass="short-box"></span>   <styletype="text/css">   .tall-box,   .short-box{ display: inline-block;               /* size, color, etc. */ }     .bottom    { vertical-align: bottom; }   .top      { vertical-align: top; } </style> 
  • 将一行内两个较大的元素垂直对齐会使得baseline移动来同时满足两个的对齐方式,并且也会调整line box的高度(左图)。再添加一个元素,如果没有因为其对齐方式而超越原有line box的边缘,则不影响line box的高度和baseline的位置(中图)。如果它超出了原来line box的边缘,line box的高度和baseline会再次调整,在这种情况下,我们的前两个方块往下挪了(右图)。

Vertical-Align: 你需要知道的所有事【译】

<!-- left mark-up --> <spanclass="tall-box text-bottom"></span> <spanclass="tall-box text-top"></span>   <!-- mark-up in the middle --> <spanclass="tall-box text-bottom"></span> <spanclass="tall-box text-top"></span> <spanclass="tall-box middle"></span>   <!-- right mark-up --> <spanclass="tall-box text-bottom"></span> <spanclass="tall-box text-top"></span> <spanclass="tall-box text-100up"></span>   <styletype="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> 

inline级元素底部的间隙

这是在试图垂直对齐 li 元素时很常见的情况。

Vertical-Align: 你需要知道的所有事【译】

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

正如你所看到的, li 元素坐在baseline上,而baseline下面是留给下标的空间,这导致了空白间隙。解决的办法很简单:将baseline上移一点。例如用 vertical-align: middle; 来对齐 li 元素。

Vertical-Align: 你需要知道的所有事【译】
<ul>   <liclass="box middle"></li>   <liclass="box middle"></li>   <liclass="box middle"></li> </ul>   <styletype="text/css">   .box    { display: inline-block;             /* size, color, etc. */ }     .middle{ vertical-align: middle; } </style> 

这种情况不会发生在具有文本内容的inline-block中,因为 内容已经使baseline往上移动了 。

inline级元素之间的水平间隙破坏布局

这主要是inline级元素本身的一个问题,但因为vertical-align的需要它们,所以还是知道比较好。

你在前一个例子的 li 中已经看到了这个间隙,它来自于你的html中inline元素之间的空白符号(空格、回车、换行)。html中多个连续的空白符号会在显示时被合并为一个空格,也就是图中的间隙。如果我们想把两个inline元素水平放置并给它们设置 width: 50% ,就无法跟额外的那个空格放在同一行,所以就会换行破坏布局(左图)。为了消除这个间隙,我们需要去除空白符号,比如使用HTMl注释(右图)。

Vertical-Align: 你需要知道的所有事【译】

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

vertical-align真相大白

就是这样,当你知道规则那就不复杂了。所以如果 vertical-align 并没有如预期发挥作用,仔细思考下面两点,就能得到结果:

  • line box的baseline和顶部及底部边缘在哪里?
  • inline级元素的baseline和顶部及底部边缘在哪里?

源于 Warrior!博客

原文  http://mxd.tencent.com/vertical-align
正文到此结束
Loading...