垂直对齐:你需要知道的所有事情(翻译)

栏目: CSS · 发布时间: 4年前

内容简介:44年前我们就把人类送上了月球, 但现在我们仍然无法在CSS中实现垂直居中。————注:因为掘金不支持自定义样式,文中基本所有的图例都无法正常显示,请诸位读者到我的博客上阅读

44年前我们就把人类送上了月球, 但现在我们仍然无法在CSS中实现垂直居中。

———— James Anderson 2013/7/20

注:因为掘金不支持自定义样式,文中基本所有的图例都无法正常显示,请诸位读者到我的博客上阅读

前言

原文地址

Yeah:yum:, 让我们来讨论一下 vertical-align 这个CSS属性。 它经常被用于对齐彼此相邻的文本和元素。就像将图标居中与和它相邻的文本。

但是它有时候看起来像一个SB,因为它所有让人摸不着头脑的规则都在起作用。 举个例子, 可能会发生这样的情况, 你改变一个元素的 vertical-align 属性之后, 它的对齐方式完全没有改变。 但是与其相邻的其他元素发生了改变! 这是在逗我呢!

所以,为了尽量减少将来的痛苦,我研究了W3C的CSS specifications, 以便搞清楚 vertical-align 的行为。

你将会在这篇文章中学到什么

  1. 内联级(inline-level)元素在线框(Line Box)中的垂直居中行为。
  2. 内联级元素和线框具有基线(Baselines),顶部(Tops)和底部(Bottoms)。
  3. 用vertical-align对齐基线,顶部和底部。
  4. 示例:如何将图标相对与相邻的文本垂直居中。
  5. 示例:如何使垂直居中的元素底部没有空隙。
  6. 示例:如何消除两个对齐的元素之间的空隙。

内联级元素在线框中的垂直居中行为

vertical-align 被用于对齐内联级元素 他们的 display 属性的计算结果为:

  • inline
  • inline-block
  • inline-table(未包含在这篇文章中)

Inline elementsare basically tags wrapping text.

内联块级元素如他们的名字一般:存在于行内的块级元素。 他们拥有 widthheight (或者由自己的内容决定)以及 paddingbordermargin

内联级元素以行的形式排列在一起。 当元素过多无法排列在一行之内, 就会在其下方创建一个新的行。 所有的行会有一个所谓的 线框(Line Box) , 它包含了行的所有内容。

**注:**这里指的是每一行都有一个线框,而不是相邻的行共用一个线框。

线框的高度受其内容的大小影响。 在下面的插图中, 线框的顶部和底部用红色的虚线表示。(原文插图)

一行高的文本。 一行矮的文本。 这也 有可能 发生。

在这些线框内, vertical-align 负责对齐每个元素。 所以, 什么是元素对齐?

关于基线(Baselines),顶部(Tops)和底部(Bottoms)

垂直对齐最重要的参照点是所涉及元素的基线。 在某些情况下, 元素的封闭盒(enclosing box)的上下边缘也很重要。 让我们来看看每个相关类型元素的基线和外边缘的位置。

内联级元素

现在你能看到相邻的三行文本。 红线表示行高的上下边缘, 绿线表示字体的高度, 蓝线表示基线。

  • 最左侧文本的行高与字体大小相等, 因此代表字体高度的绿线和代表行高的红线重叠成了一条线。
  • 中间的文本的行高是字体大小的两倍。
  • 右侧的文本的行高是字体大小的一般。

内联级元素的外边缘与其行高的上下边缘对齐。 行高小于字体的大小无关紧要。 所以在上图中, 红线表示的是外边缘。

内联级元素的基线, 字符位于其中。 在图中由蓝线表示。 粗略的讲, 基线位于字体高度中间的某个位置。 详细信息见W3C 规范

inline-block元素

从左到右你能看到:一个具有内容(一个“C”)的 inline-block 元素, 一个具有内容且 overflow: hiddeninline-block 元素, 一个没有内容(但是指定了 height )的 inline-block 元素。 红色表示外边距, 黄色表示边框, 绿色表示内边距, 蓝色表示内容。 在每个 inline-block 元素中基线都用蓝线表示。

inline-block 元素的外边缘 是其外边距顶部和底部的边缘。 在图例中用红线表示。

inline-blick 元素的基线 取决于元素是否有in-flow内容:

  • 在具有in-flow内容的情况下, inline-block 元素的基线是正常流(normal flow)中最后一个内容元素的基线(图例中左侧的例子)。 最后一个元素根据自己的规则找到自己的基线。
  • 在具有in-flow内容且 overflow 属性的计算结果不是 visiable 的情况下,基线是外边距的底部边缘(图例中中间的例子)。 所以,它跟 inline-block 元素的底部边缘相同。
  • 如果不存在in-flow内容, 基线也是外边距的底部边缘(图例中右侧的例子)。

Line Box

This can happen.

你已经在上面看到过这个图例了。 这次我也画出了线框的文本框的上下边缘(绿线)和基线(蓝线)。 还给文本元素加上了灰色的背景以突出其区域。

线框的 顶部 于最顶部元素的顶部对齐, 线框的 底部 于最底部元素的底部对齐。 这在上面的图例中以红线所示的方框表示。

线框的基线是可变的:

CSS 2.1 does not define the position of the line box's baseline.

CSS 2.1没有定义线框的基线位置。

— theW3C Specs

vertical-align 这个属性上,基线(Baseline)大概是最混乱的部分。 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.

因为线框的基线是不可见的,因此它并不是显而易见的。 但是我们能很容易地使它可见。 只需要在行的开头添加一个字符, 比如我在图例中添加了一个“x”。 如果这个字符没有对齐任何地方, 默认情况下会位于基线上。

文本框(Text Box)

我们将线框基线周围的内容称之为 文本框 。 文本框可以简单地看作线框内没有任何对齐的 inline 元素。 它的高度等于父元素的字体大小。 因此, 文本框仅仅包含线框的无格式文本。 该框在上面的图例中用绿线表示。 因为文本框于基线相关联, 当基线移动时文本框也会移动。

注:这个文本框在W3C规范中被称为strut。

啊,这是最难的部分了。 现在我们知道了一切, 要把事情弄清楚 ,让我们快速总结一下最重要的部分:

  • 有一个区域叫做线框(Line Box),这是发生垂直对齐的区域。 他有一条基线(Baseline), 一个文本框(Text Box)和上下边缘。
  • 内联级元素。 它们是对齐的对象, 它们有一条基线和上下边缘。

用vertical-align对齐基线,顶部和底部

By using vertical-align the reference points mentioned in the list above are set into a certain relationship.

相对于线框的基线对齐

x baseline
  • baseline: 元素的基线恰好于线框基线的重叠。
  • sub: 元素的基线位于线框基线下方。
  • <percentage>: 元素的基线相对于线框的基线移动的距离是相对于行高的百分比。
  • <length>: 元素的基线相对于线框的基线移动的距离是一个绝对值

一个特例是 vertical-align: middle ,如下图例:

x
  • middle: 元素上下边缘的中点于线框基线加上x高度的一半对齐。

相对于线框的文本框对齐

text-top text-bottom

也可以在相对于线框的基线对齐的情况下列出这两个案例, 因为文本框的位置由基线决定(见文本框(Text Box))。

  • text-top: 元素的上边缘于线框中文本框的上边缘对齐。
  • text-bottom: 元素的下边缘于线框中文本框的下边缘对齐。

相对于线框的外边缘对齐

  • top: 元素的上边缘于线框的上边缘对齐。
  • bottom: 元素的下边缘于线框的下边缘对齐。

当然W3C中也有正式的定义

Why Vertical-Align Behaves The Way It Behaves

我们现在可以在某些情况下仔细地研究垂直对齐了。我们还会处理一些可能出问题的情况。

居中一个图标

一个困扰我的问题如下:我有一个图标, 我想在一行文本旁边居中放置它。 仅仅给图标设置 vertical-align: middle 似乎不是一个令人满意的居中方案。 看看这个示例:

Centered?

Centered!

<!-- 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>
复制代码

这是一个相同的示例, 但是我画了一些你已经从上文中看到过的辅助线(不知道为什么人们能一眼看出这里细微的不协调):

x

Centered?

Centered?

这让我们的问题有些苗头了。 因为左边的文本完全没有对齐图标, 它跟基线对齐了。 现在的情况是,通过给图标设置 vertical-align: middle 我们将图标的中点和小写字母“x”的中点(即x-height的一半)对齐。所以有升部和降部的字符就会突出。

注:升部和降部分别指字母向上超出主线和向下超出基线的部分。来自维基百科

注:x-height(译名:X高度)是一个特有名词,是指字母的基本高度,精确地说,就是基线(英语:baseline)和主线之间的距离。特别的,它指称一个字体中小写字母x的高度(这也是这个词的语源)。来自维基百科

在右边, 我们使整个字体区域对齐垂直方向上的中点。 这时文本的基线向线框的基线的下方移动了一点以对齐中点。 很明显这是一个完美的对齐的方案。

线框基线的移动

使用 vertical-align 时, 有一个常见的陷阱:基线的位置会被行内所有的元素影响。 让我们做一个假设, 当一个元素以某种方式对齐时, 线框的基线一定会移动。 大多数垂直对齐(除了顶部和底部对齐)都是相对于基线对齐的, 这会导致线框内的其他元素重新调整其位置。

看看这些示例:

  • 如果一个元素的高度等于整行的高度, vetical-align 对这个元素是无效的。 因为没有多余的空间让它移动。 为了相对于线框的基线对齐, 线框的基线就必须移动。 较矮的盒子的 vertical-align 属性是 baseline 。 左侧较高的盒子的 vertical-align 属性是 text-bottom 。 右侧较低的盒子的 vertical-align 属性是 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>
复制代码

就算较高元素的 vertical-align 属性取其他值, 也会显示如上相同的行为。

  • 即使设置 vertical-align 的值为 bottom (左侧)或 top (右侧), 基线也会移动。 这很奇怪, 因为这与基线毫无关系。
<!-- 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 属性为 middle , 且上下都没有超过线框的边缘。 因此既不会影响线框的高度也不会影响线框基线的位置。 如果它 超过 了线框的边缘, 那么线框高度和基线又会移动了。 在这种情况下, 前面两个元素被 下来了。
<!-- 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>
复制代码

内联级(inline-level)元素下方可能会有一点小空隙

看看这个示例。 如果你尝试垂直对齐列表中的 li 元素很有可能碰到过这种情况。

<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>
复制代码

如你所见, 列表项位于基线上。 基线下方留出了一些空间来容纳文本的降部。 这正是我们看到空隙的原因。 如何解决这个问题? 既然文本是与基线对齐才留出了空隙,那么我们只需要将文本与其他的位置对齐就好了。 举个例子, 将列表项设置为 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>
复制代码

具有内容的 inline-block 元素不会发送这种情况,因为基线已经位于内容的上方了。

内联级元素之间的空隙会破坏布局

这主要是内联级元素自身的问题, 但是因为这是垂直对齐的一个要求,因此了解这一点是很好的。 (不太理解这句话, 下面是原文。)

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.

你能在第一个示例中的列表项看到空隙。 空隙来自内联元素之间的空白。 内联元素之间的所有空白被合并为一个空格。 如果我们并排放置两个内联元素并且给它们的 width 属性赋值 50% 。那么它们所占据的空间就是两个 50% 加上一个空格。 显然这超出了一行。 因此该行被分为两行, 这破坏了布局(左侧)。 如果要消除空隙,我们就需要删除空格,例如使用html注释(右)。

50% wide

50% wide

50% wide

50% wide

<!-- 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>
复制代码

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持 码农网

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

RESTful Web Services Cookbook

RESTful Web Services Cookbook

Subbu Allamaraju / Yahoo Press / 2010-3-11 / USD 39.99

While the REST design philosophy has captured the imagination of web and enterprise developers alike, using this approach to develop real web services is no picnic. This cookbook includes more than 10......一起来看看 《RESTful Web Services Cookbook》 这本书的介绍吧!

CSS 压缩/解压工具
CSS 压缩/解压工具

在线压缩/解压 CSS 代码

JSON 在线解析
JSON 在线解析

在线 JSON 格式化工具

html转js在线工具
html转js在线工具

html转js在线工具