【渡一教育】常见布局错位问题解决办法

458 阅读6分钟

一个常见的bug:


设置两列布局,左侧为导航条右侧为内容区,左侧导航条有50px的padding,并且含有三条导航,右侧只展示一个内容区,代码如下:


常见布局错位问题解决办法


效果如下:


常见布局错位问题解决办法


相信大家都遇到过这样的问题,也都知道解决这个问题我们只需要添加一个vertical-align这个属性就可以了,但是这是为什么呢?今天我们就来探讨一下vertical-align这个问题。


1. vertical-align是什么属性?

vertical-align是设置一个含有行级特点的元素垂直方向对齐方式的属性。


2. vertiacl-align作用的前提

vertical-align只能作用在display的值为inline、inline-block、inline-table或table-cell的元素上。


因此默认情况下span、strong、em等内联元素,img、button、input等替换元素,非html规范的自定义标签元素,以及td单元格都是支持vertical-align属性的。


但在css的世界钟,总有一些“搅屎棍”影响着默认的状态,比如L浮动和绝对定位会让元素块状化,因此在vertical-align与float和position:absolute一起使用的时候是没有作用的。


3. vertical-align对齐的原理

根据W3C Spec中对vertical-align属性的定义:


This property affects the vertical positioning inside a line box of the boxes generated by an inline-level element.

翻译:此属性影响由内联级元素生成的line-box内的垂直位置。


那么什么是line box?同样来自W3C Spec定义line box :


The rectangular area that contains the boxes that form a line is called a line box.

翻译:包含形成一排内容的方框的矩形区域称为线框。


既然vertical-align是垂直方向上的对齐,我们就要注意line box的高度,那么line box的高度怎么计算呢?我们还是看下W3C Spec中的定义:


The height of a line box is determined by the rules given in the section on line height calculations.

翻译:line box的高度由文本的行高计算给出的规则决定。


转换成人话就是:

一个line box的高度是的计算方式如下:line box中的每一个行内元素都将加入到计算过程,如果是元素inline的则取其line-height的值,如果元素是inline-block或者是inline-table则取其margin-box的高度,最后这些值的最大值,即为line box的高度了。


4. 在vertical-align的世界中都有哪些对齐方式?


(1)baseline (默认值)

相对于基线对齐,那么问题来了line box的基线在哪?

我们先看一个代码

常见布局错位问题解决办法


看下效果:

常见布局错位问题解决办法


下面我们添加一下vertical-align这个属性让第一个inline元素的vertical-align的值为top,第二个inline元素的vertical-align值为bottom,中间inline-block元素和图片添加一个margin值为10px;在最后再加上一个span标签将其vertical-align设置为默认值baseline


代码如下:

常见布局错位问题解决办法


效果如下:

常见布局错位问题解决办法

下面我们找到line box

常见布局错位问题解决办法


下面我们把每个元素自身的盒子画出来

常见布局错位问题解决办法


w3c标准中并没有说明line-box的baseline的位置,这一点很让人困惑,baseline的位置需要满足vertical-align属性的值以及让line-box的高度最小等条件,是一个很灵活的参数。虽然line-box的baseline是不可见的,但是可以很轻松的将它可视化出来,如下图,默认情况下基线为书写字母的四线格中倒数第二条线。


常见布局错位问题解决办法


由此可以轻松地将我们的实例程序的baseline画出,如下图:

常见布局错位问题解决办法


由上图可见

line-box的基线是一个不固定的位置,对于图片类的不确定元素默认的基线再margin盒的底部


2)top 和bottom

上述案例中我们可见设置vertical-align:top和vertical-align:bottom的元素所在的位置为line box的顶部和底部。即值为top和bottom代表垂直方向按照line box的盒子顶部与底部对齐


3) sub 和 super

sub:行内元素盒的基线相对于line-box的基线,偏下一点(偏多少浏览器说了算);

super:行内元素盒的基线相对于line-box的基线,偏上一点(偏多少浏览器说了算);

为第一个span添加vertical-align:sub;第二个span添加vertical-align:super效果如下

常见布局错位问题解决办法


4)middle

MDN中定义middle:行内元素盒的中心相对于行盒的基线,偏上1/2 x-height


那么哪里是x-height呢?


维基百科中是这么说的:


Typically, this is the height of the letter x in the font (the source of the term), as well as the v, w, and z. (Curved letters such as a, c, e, m, n, o, r, s, and u tend to exceed the x-height slightly, due to overshoot.) One of the most important dimensions of a font, x-height is used to define how high lower-case letters are compared to upper-case letters.

有道翻译一下:

通常,这是字体中字母x的高度(术语的来源),以及v、w和z的高度。字体最重要的维度之一,x-height用于定义小写字母与大写字母的比较高度。


即:


常见布局错位问题解决办法


也就是vertical-align:middle表示元素向上偏移二分之1的x-height大小


再次修改我们的案例将第一个span的vertical-align的值设置成middle


常见布局错位问题解决办法


此时你会发现设置vertical-align:middle的元素基线会向下移而不是向上移动,这是因为middle对齐的不再是基线而是元素自身的中心位置与linebox的基线位置如下middle的位置。


常见布局错位问题解决办法


5)text-top和text-bottom

text-top:相对于父级元素下文本的顶部对齐

text-bottom:相对于父级元素下文本的底部对齐


一个案例:

代码:


常见布局错位问题解决办法


效果:

常见布局错位问题解决办法

常见布局错位问题解决办法


6)具体像素

元素的基线相对于line box的基线通过绝对值的大小进行移动。


一个案例:

代码:

常见布局错位问题解决办法


效果:

常见布局错位问题解决办法

常见布局错位问题解决办法


7)百分比

元素的基线移动相对于line box的基线通过相对于line-height的百分比的值来移动。


一个案例:

代码:

常见布局错位问题解决办法


效果:

常见布局错位问题解决办法

常见布局错位问题解决办法


回到最初的起点,辣个bug


设置两列布局,左侧为导航条右侧为内容区,左侧导航条有50px的padding,并且含有三条导航,右侧只展示一个内容区


代码如下:


常见布局错位问题解决办法


效果如下:

常见布局错位问题解决办法


上述效果中右侧内容区部分明明没有设置任何的margin和定位却向下偏移了一些,导致这样效果的原因就是在多行的文字中基线的位置。


那么问题又来了多行文字组成的块区域基线在哪?

查看父级的基线我们只需要给父级加上一个文本节点x,如下

常见布局错位问题解决办法


效果如下:

常见布局错位问题解决办法


这样line box的基线可显而知

常见布局错位问题解决办法


由此我们可以得出结论:如果多行元素会影响linebox的基线位置下移至最高的元素最后一行的基线处。


当你知道了规则,vertical-align就没那么复杂了吧。

如果vertical-align并没有按照你想的那样行动,问自己两个问题:

  • line box的顶部与底部边缘和基线在哪里?
  • 元素的顶部与底部边缘和基线在哪里?