Home  >  Article  >  Web Front-end  >  CSS深入理解vertical-align和line-height的基友关系_html/css_WEB-ITnose

CSS深入理解vertical-align和line-height的基友关系_html/css_WEB-ITnose

WBOY
WBOYOriginal
2016-06-21 08:45:541354browse

一、想死你们了

几个星期没有写文章了,好忙好痒;个把月没有写长篇了,好忙好想;半个季度没在文章中唠嗑了,好痒好想。

后面一栋楼有对夫妻在吵架,声音雄浑有力,交锋酣畅淋漓,还以为只有小乡镇才有这架势,哦,突然想起来,我就是住在上海郊外的小乡镇上。

刚刚买了几十股京东的股票,第一次玩这个,看好京东的发展。其实股价21的时候就打算入手了,但是,转外汇的时候,提示,要工作时间。然后一忙二忘,等现在入的时候,已经涨了20%多了,科科,肥皂弄人啊!写到这里的时候,忍不住拿出手机一看,哎呦,不错哦,盈利28刀,孩子的半罐奶粉钱有了,哈哈!

说起肥皂,让我想起了《监狱学院》,科科~

原来,肥皂和基友的传说已经传播到了11区。岂止啊,除了2次元,代码次元也深受其爱,比方说CSS届的vertical-align和line-height就是典型的表面上看上去大相径庭,实际上是大进后庭的断背好基友啊!

没错,就是这么狗血!

乡下人不打诳语,下面我就好好跟大家八卦下,vertical-align和line-height之间令人发指的基友关系!

二、表现明显的断背基情

众所周知,vertical-align支持很多属性值,足足可以组成一个足球队了:

/* 关键字值 */vertical-align: baseline;vertical-align: sub;vertical-align: super;vertical-align: text-top;vertical-align: text-bottom;vertical-align: middle;vertical-align: top;vertical-align: bottom;/* <长度> 值 */vertical-align: 10em;vertical-align: 4px;/* <百分比> 值 */vertical-align: 10%;/* 全局值 */vertical-align: inherit;vertical-align: initial;vertical-align: unset;

其中,有个属性值暴露了vertical-align和line-height之间的基友关系,大家猜猜看是哪个属性值?

哇塞,好厉害!居然被大家一眼就看出来了,没错,就是“百分比值”。

vertical-align的百分比值不是相对于字体大小或者其他什么属性计算的,而是相对于line-height计算的。举个简单的例子,如下CSS代码:

{  line-height: 30px;  vertical-align: -10%;}

实际上,等同于:

{  line-height: 30px;  vertical-align: -3px;    /* = 30px * -10% */  }

CSS属性何其多,偏偏跟line-height有一腿,这不是有基情那是什么?

//zxx: IE6/IE7浏览器下的vertical-align的百分比值不支持小数line-height

三、背地里无处不在的基友关系

//zxx: 注意 ,vertical-align和line-height的地下基友关系从HTML5文档声明开始的,因此,以下探讨的现象,都是在页面为HTML5声明前提下,类似下面的doctype:

<!doctype html><html>

另外,下面很多效果直接就是真实演示,因此,请使用现代浏览器观摩下面的内容。如果发现某些行为与描述不匹配,且浏览器正常,那可能是因为你访问的并不是 原出处 。

① 基本现象

要八卦vertical-align和line-height之间的关系,我们不妨从一个极其简单的现象入手。假设,我们有一个

标签,然后,里面有一张CSS深入理解vertical-align和line-height的基友关系_html/css_WEB-ITnose图片,我们的HTML代码就是这样子:
<div><img  src="mm1.jpg" alt="CSS深入理解vertical-align和line-height的基友关系_html/css_WEB-ITnose" ></div>

然后,表现就是一张图片呈现,类似下面这样:

恩,看上去很正常,一切都是理所当然。然而,如果我们给这个

元素增加一个背景色,例如淡蓝色:
<div style="background-color:#e5edff;"><img  src="mm1.jpg" alt="CSS深入理解vertical-align和line-height的基友关系_html/css_WEB-ITnose" ></div>

则会是下面这样:

会发现图片下面有一段空白空间:

想必大家都遇到过类似问题,不知大家有没有思考过,为什么图片下面有留有一段间隙呢?

实际上,这段空白间隙就是vertical-align和line-height携手搞的鬼!

首先,大家一定要意识到这么一点: 对于内联元素,vertical-align与line-height虽然看不见,但实际上「到处都是」!

因此,对于内联元素各种想得通或者想不通的行为表现,基本上都可以用vertical-align和line-height来解释,以及进行行为矫正,然而,要深入理解这些行为表现,还是需要狠花一番功夫的,因此,下面的内容,请确保你有半小时充足时间细细阅读,别的地方可是看不到的。

② 幽灵空白节点

「幽灵空白节点」这个概念我自己命名的,注意,是我个人YY出来的,是我自己便于理解某些行为特征提出的概念。规范可能有类似的概念,但名称并非这个。 W3C规范虽然有很多行为的解释和说明,但是,毕竟官方的东西,要求严谨正式,但是,也会有太干太涩的感觉。如果快速掌握和理解这些行为表现呢?就我个人而言,从两方面入手: 1.情感化认知2. 具象化思维

例如,我称vertical-align和line-height为好基友(包括以前称浮动和绝对定位是兄弟),就是“情感化认知”;而这里的「幽灵空白节点」就是“具象化思维”。

那「幽灵空白节点」是个什么意思呢?

在HTML5文档声明下,块状元素内部的内联元素的行为表现,就好像块状元素内部还有一个(更有可能两个-前后)看不见摸不着没有宽度没有实体的空白节点,这个假想又似乎存在的空白节点,我称之为“幽灵空白节点”。//zxx: 自己捣腾的概念,不是权威,欢迎其他小伙伴反馈权威解释

抽象了这个概念,绝对定位与text-align的一些行为表现,以及这里的行为表现,就好理解了。

还是上面的图片下边缘留空隙的例子,实际上,这种行为表现,就跟图片前面或者后面有一个宽度为0的空格元素表现是一致的。但是,空格是透明的,为了便于大家理解,我就直接使用很明显的匿名inline box, 也就是字符代替。如下,大家会发现,图片下面的间隙,依旧是那个间隙。

zxx

下面要解释这个间隙就好解释了。下面,我们让新增的文本inline-block化,然后弄个白色背景,显示其占据的高度。

zxx

会发现,图片下面的间隙,依旧是那个间隙。但是,我们的理解就好理解了。回答下面几个问题,我们就知道表现的原因了:

  • vertical-align默认的对齐方式是?

  • 后面zxx文字的高度从何而来?

  • 上面2个问题就很简单了:

  • vertical-align默认值是baseline, 也就是基线对齐。而基线是什么,基线就是字母X的下边缘(参见“ 字母’x’在CSS世界中的角色和故事 ”一文)。所以,妹子图片的下边缘就和后面zxx中的字母x下边缘对齐(见下图)。而字符zxx本身是有高度的,对吧,于是,图片下面就留空了。

  • 而zxx文字的高度是由行高决定的。

  • 因此,简单的图片下面留白行为表现,本质上,就是vertical-align和line-height背地里搞基造成的。

    知道了问题的原因,我们就可以对症下药,准确搞定图片下面我们不希望看到的间隙。怎么搞呢?一对基友,vertical-align和line-height我们随便搞定一个就可以了。

    比方说vertical-align.

    1. 让vertical-align失效

    图片默认是inline水平的,而vertical-align对块状水平的元素无感。因此,我们只要让图片display水平为block就可以了,我们可以直接设置display或者浮动、绝对定位等(如果布局允许)。例如:

    img { display: block; }

    则妹子就会变这样:

    下面的空隙不见了。

    2. 使用其他vertical-align值

    告别baseline, 取用其他属性值,比方说bottom/middle/top都是可以的。

    vertical-align:bottom vertical-align:middle vertical-align:top

    zxx

    3. 直接修改line-height值

    下面的空隙高度,实际上是文字计算后的行高值和字母x下边缘的距离。因此,只要行高足够小,实际文字占据的高度的底部就会在x的上面,下面没有了高度区域支撑,自然,图片就会有容器底边贴合在一起了。比方说,我们设置行高5像素:

    div { line-height: 5px; }

    zxx

    4. line-height为相对单位,font-size间接控制

    如果line-height是相对单位,例如line-height:1.6或者line-height:160%之类,也可以使用font-size间接控制,比方说来个狠的,font-size设为大鸡蛋0, 本质上还是改变line-height值.

    div { font-size: 0; }

    zxx

    ③ 基本现象衍生:垂直居中

    由于「幽灵空白节点」的存在,因此,我们可以进一步衍生,实现其他更实用的效果,比方说任意尺寸的图片(或者内联块状化的多行文字)的垂直居中效果。就是借助本文的两位男主角,vertical-align和line-height。

    你想啊,图片后面(前面)有个类似空格字符的节点,然后就能响应line-height形成高度,此时,图片再来个vertical-align:middle,当当当当,就可以和这个被行高撑高的「幽灵空白节点」(近似)垂直对齐了。

    例如:

    div { line-height: 240px; }img { vertical-align: middle; }

    然后就会这样子:

    不过上面的效果并不是完全的垂直居中,只是近似(稍微仔细看可以看出来)。为什么只是近似呢?那是因为「幽灵空白节点」还是默认的基线对齐。因此,实际上,此时的效果是图片的中线对齐后面幽灵字符的基线。

    嘛嘛,单纯的文字还是太苍白了,截个图示意下吧:

    因此,要想完全垂直居中,最先想到的方法就是让后面的“幽灵字符”也是vertical-align:middle,然而,呵呵,既然称之为“幽灵”就表示不会受非继承特性的属性影响,所以,根本没法设置vertical-align:middle,除非你自己创建一个显示的内联元素。

    我们就没有办法了吗?当然不是,“幽灵字符”可以受具有继承特性的CSS属性影响,于是,我们可以通过其他东西来做调整,让字符的基线和中线在一起,或者说在一个位置上就可以了。有人可能要疑问了,这能行吗?啊,是可以的。

    对于字符而言,基线的定义是什么?是字符x的下边缘,而中线的定义是什么,是基线往上1/2字符x的高度,于是,我们就可以列个公式,已知:x = x - 1/2 * x, 求x? 显然,x就是0,于是,我们只要让字符x的肉眼视觉高度为0就可以了。怎么搞?很简单,font-size:0, 于是,完全垂直居中就是:

    div { line-height: 240px; font-size: 0; }img { vertical-align: middle; }

    结果是:

    处女座的你,是不是看过去舒服多啦!?

    这种通过line-height定高,元素vertical-align:middle垂直居中的方法不仅适用于现代浏览器,连IE7浏览器也是支持的:

    不过和其他浏览器再使用上还是有些需要注意的地方,就是,HTML不能这样:

    <div><img  src="mm1.jpg" alt="CSS深入理解vertical-align和line-height的基友关系_html/css_WEB-ITnose" ></div>

    而是需要在图片标签结束处留下空格后者换行:

    <div><img  src="mm1.jpg" alt="CSS深入理解vertical-align和line-height的基友关系_html/css_WEB-ITnose" ><!-- 这里要折行或空格 --></div>

    ④ 复杂现象

    多年前曾分享过“ text-align:justify下列表的两端对齐布局 ”的技术,其中,为了让任意个数的列表最后一行也是对齐排列,在列表最后会辅助列表等宽的空标签元素来占位,类似下面红色高亮HTML代码:

    .justify-fix { display: inline-block; width: 128px; }
    <div   style="max-width:90%"><img  src="img/mm1.jpg"    style="max-width:90%" alt="CSS深入理解vertical-align和line-height的基友关系_html/css_WEB-ITnose" ><img  src="img/mm1.jpg"    style="max-width:90%" alt="CSS深入理解vertical-align和line-height的基友关系_html/css_WEB-ITnose" ><img  src="img/mm1.jpg"    style="max-width:90%" alt="CSS深入理解vertical-align和line-height的基友关系_html/css_WEB-ITnose" ><img  src="img/mm1.jpg"    style="max-width:90%" alt="CSS深入理解vertical-align和line-height的基友关系_html/css_WEB-ITnose" ><i class="justify-fix"></i><i class="justify-fix"></i><i class="justify-fix"></i></div>

    .justify-fix { display: inline-block; width: 128px; }.outline .justify-fix { outline: 1px dashed red; }

    为了节约空间,我就使用小图示意:

    同样的,在白色背景下,似乎看上去效果还不赖,但是,如果给div容器加个背景色~~

    会惊讶的发现,下面多了很大一块间隙(如下截图):

    为了便于大家看其究竟,我把占位i元素outline高亮下,于是,效果如下:

    结果会发现,上面巨大的空隙是由占位i元素上面和下面的间隙共同组成的。

    下面问题来了:上面的间隙是如何产生的?下面的间隙是如何产生的?如果去除这些间隙呢?

    很多时候,复杂问题是由简单问题组合而成的,实际上,这里的间隙现象的始作俑者和上面的简单现象一样,都是vertical-align和line-height搞基带来的不好的影响。

    按照之前问题解决方法,我们可以直接来个line-height:0解决垂直间隙问题:

    div { line-height: 0; }

    结果图片和图片之间的间隙是没有了,但是,图片和最后的占位元素之间依然有个几像素的间距, ,啊啊啊啊,这究竟是什么鬼?

    简单现象的背后往往有大的学问,接下来是本文的高潮了,究其原因,要说到inline-block元素和基线baseline之间的一些纠缠的关系。

    ⑤ inline-block和baseline

    CSS2的可视化格式模型文档中有一么一段话:

    The baseline of an ‘inline-block’ is the baseline of its last line box in the normal flow, unless it has either no in-flow line boxes or if its ‘overflow’ property has a computed value other than ‘visible’, in which case the baseline is the bottom margin edge.

    英文看得眼睛大,于是我中文直译了下:

    ‘inline-block’的基线是正常流中最后一个line box的基线, 除非,这个line box里面既没有line boxes或者本身’overflow’属性的计算值而不是’visible’, 这种情况下基线是margin底边缘。

    这段文档中出现了很多专有名词line box, line boxes等,这些是内联盒子模型中的概念,是CSS进阶必备知识。我在“ 浮动深入理解(一) ”一文的中间穿插介绍了该模型。//zxx: 我现在后悔了,内联盒子模型当初应该直接独立成一篇文章,这样其他文章可以很干净地引用,所谓文章的模块化书写

    如果大家没有足够精力去学习之,可以先看下面这张图:

    由于上面的译文是直译的,理解起来还是有些拗口,我使用通俗的话描述就是: 一个inline-block元素,如果里面没有inline内联元素,或者overflow不是visible,则该元素的基线就是其margin底边缘,否则,其基线就是元素里面最后一行内联元素的基线。

    纳尼,还是没反应过来?

    那我们看下面这个例子,应该就知道什么意思了。

    两个同尺寸的inline-block水平元素,唯一区别就是一个空的,一个里面有字符,代码如下:

    .dib-baseline {  display: inline-block; width: 150px; height: 150px;  border: 1px solid #cad5eb; background-color: #f0f3f9;}
    <span class="dib-baseline"></span><span class="dib-baseline">x-baseline</span>

    .dib-baseline { display: inline-block; width: 100px; height: 100px; border: 1px solid #cad5eb; background-color: #f0f3f9; }

    结果,科科:

    x-baseline

    会发现,明明尺寸、display水平都是一样的,结果呢,两个却不在一个水平线上对齐,为什么呢?哈哈,上面的规范已经说明了一切。第一个框框里面没有内联元素,因此,基线就是容器的margin下边缘,也就是下边框下面的位置;而第二个框框里面有字符,纯正的内联元素,因此,第二个框框就是这些字符的基线,也就是字母x的下边缘了。于是,我们就看到了框框1下边缘和框框2里面字符x底边对齐的好戏。框框2有个小彩蛋,点击可以toggle其innerHTML,会发现,如果框框2里面没文字,就和框框1举案齐眉了。

    下面我们要做一件很有必要的事情,用来帮助我们理解上面复杂例子在line-height值为0后的表现,什么事情呢?哈,同境界模拟,我们也设置框框2的line-height值为0,于是,就会是下面这样的表现:

    x-baseline

    知道框框2为何又下沉了一点吗?

    因为字符实际占据的高度是由行高决定的,当行高变成0的时候,字符占据的高度也是0,此时,高度的起始位置就变成了字符content area的垂直中心位置,于是,文字就一半落在看看2的外面了。

    由于文字字符上移了,自然基线位置(字母x的底边缘)也往上移动了,于是,两个框框的垂直落差就更大了。

    OK,明白了上面的简单例子,也就能明白上面的复杂例子。紧接着,如果我们在最后一个占位的元素后面新增同样的x-baseline字符,则:

    x-baseline

    大家是不是就可以明白原因所在啦!

    额~居然还有小伙伴皱眉头,那我再用文字解释下:

    现在行高line-height是0, 则最后的x-baseline的垂直中线就和上面一列的图片对齐,而基线呢,就在中线下面差不多半个x的高度地方,而这个高度落差就是最后图片和容器的间隙高度值,因为前面的是个空元素,基线是自身的底部,哈哈,造业啊!

    OK,一旦知道了现象的本质,我们就能轻松对症下药了!要么改造占位元素的基线、要么改造“幽灵空白节点”的基线位置、要么使用其他vertical-align对齐方式~

    首先,来个最有意思的方法,对吧, 改造占位元素的基线 。这个很简单,对吧,只要在空的元素里面随便放几个字符就可以了,例如,里面有个x:

    xx-baseline

    会发现,间隙没有了! 为什么呢?哈哈,因为元素的基线和“幽灵空白节点”的基线位置现在一致了,没有了错位,自然就不会有间隙啦!

    改造“幽灵空白节点”的基线位置,哈哈,使用font-size,字体足够小时,基线和中线会重合在一起,什么时候字体足够小呢,就是0. 于是,CSS代码(line-height如果是相对值,line-height:0也可以省掉):

    div { font-size: 0; }

    使用其他vertical-align对齐方式,就是让两端对齐的列表元素vertical-align:top/bottom/...之类。

    div { line-height: 0; }.justify-fix { display: inline-block; width: 128px; vertical-align: top; }

    最后的效果是:

    恩恩,各种方法都完美解决了垂直间隙的问题,来,各个大大的赞!

    四、基友关系暴露之后

    至此,vertical-align和line-height的断背基友关系算是彻底暴露了,而且,从行为表现上来看,line-height是攻,vertical-align是个受。而很多内联元素的行为表现,就是这对基友搞七搞八一起搞出来的。

    以前,关系处于地下的时候,我们可能不会明白,为何男厕所的卷纸用得比女厕所还快;但是,现在关系暴露了,很多以前我们想不明白的事情一下子就豁然开朗了。

    因此,我们要以正确地心态去看待这对好基友,毕竟,他们可以CSS届非常重要的两个主力大将。

    本文牵扯的知识点甚多,建议大家如果想在重构领域有所造诣,很多基本的却很深入的东西是很有必要弄透的。篇幅有限,有不少知识点都是一笔带过的,大家若有疑问,可以自己去检索与研究,例如,vertical-align各个值的规范解释,内联盒子模型,等等。也欢迎各种方式交流。

    文章都是周末熬夜写的,你知道的,现在不是当年,眼皮像灌了水银,因此,文章有表述或书写错误的地方在所难免,欢迎指正!

    感谢阅读,周末愉快!另外祝贺中国队400米接力获得银牌。

    var funImgVt = function(input) { var imgvt = document.getElementById("imgVt");if(imgvt) { imgvt.style.verticalAlign=input.value; } };

    本文为原创文章,包含脚本行为和样式控制,会经常更新知识点以及修正一些错误,因此转载请保留原出处,方便溯源,避免陈旧错误知识的误导,同时有更好的阅读体验。

    本文地址: http://www.zhangxinxu.com/wordpress/?p=4925

    (本篇完)

    Statement:
    The content of this article is voluntarily contributed by netizens, and the copyright belongs to the original author. This site does not assume corresponding legal responsibility. If you find any content suspected of plagiarism or infringement, please contact admin@php.cn