从一个内联元素布局引发对line-height的探讨
一、前言
line-height
这个属性对于各位前端的小伙伴来说并不陌生。在之前写页面的时候碰到过一个该属性相关的问题,在查阅资料后决定跟大家分享一下我所理解的line-height
。所讲述的内容不一定都是正确的,仅供参考。
二、line-height
定义
文档规范
line-height
CSS 属性用于设置多行元素的空间量,如多行文本的间距。对于块级元素,它指定元素行盒(line boxes)的最小高度。对于非替代的 inline 元素,它用于计算行盒(line box)的高度。
属性值
属性 | 描述 |
---|---|
normal | 默认值。合理的行间距。根据浏览器和字体’font-family’不同而不同。 |
number | 设置数值,此数值会与当前的字体尺寸相乘来设置行间距。 |
length | 设置固定的行间距。 |
% | 基于当前字体尺寸的百分比间距。 |
inherit | 规定应该从父元素继承line-height属性的值 |
三、遇到的问题
相信大家都有写过这样一个布局 一个大标题,然后接着一个小标题,需要垂直居中
.title {
font-size: 20px;
line-height: 20px;
}
.sub-title {
font-size: 14px;
line-height: 20px;
}
<div>
<span class="title">大标题</span>
<span class="sub-title">小标题</span>
</div>
两个相邻的内联元素,字体一大一小。畅想的结果是两个 span
的高度都是20px, div
的高度也是20px,多么完美,但结果往往不近人意….
div
的高度为22.4 .title
的高度为26.4 .sub-title
的高度为19
那么问题来了:为什么没有一个元素的高度为20?
然而 规范 告诉我们,对于非替代的 inline 元素,它用于计算行盒(line box)的高度。
这里引出了两个概念:替代元素、行盒(line-box)
替代元素
替代元素是指内容可以替换的元素,实际上就是content box可以被替换的元素。如存在src=””属性的
<img>
<audio>
<video>
<iframe>
元素和可以输入文本的<input>
<select>
<textarea>
元素等。
所有替换元素都是内联元素,默认display属性是inline或inline-block(除了input[type=”hidden”]默认display: none;)。替换元素有自己默认的样式、尺寸(根据浏览器不同而不同),而且其vertical-align属性默认是bottom(非替换元素默认值是baseline)。
行盒-line box
由内联元素组成的每一行都是一个行框盒子。行框盒子由一个个内联盒子组成,如果换行,那就是两个行框盒子。比如一个不换行的的p标签,就存在一个行框盒子。值得注意的是,如果给元素设置
display:inline-block
,则创建了一个独立的行框盒子。line-height
是作用在行框盒子上的,并最终决定高度
一行有很多行内框,而行框的高度就是包含这一行行内框最高点和最低点的
然后继续探前面的问题
这里的span
标签为inline元素,高度只会受到内容区域大小的影响
font-size
设置为30px时
为了查看实际高度,我们给 span
加上inline-block属性, 使其变成内行框
.title {
display: inline-block;
font-size: 28px;
line-height: 20px;
}
.sub-title {
display: inline-block;
font-size: 14px;
line-height: 20px;
}
可以看到 设置为inline-block
的span
标签高度正常。但是为什么div高度还是 23 ?
由上图可以看到,.title
和 .sub-title
是没有对齐的,由此可以思考是不是元素没有对齐而撑开了div的高度
为此给.sub-title
加个 vertical-align
样式继续探讨
当vertical-align:top
时
可以看见div
的元素高度小了1px, 可以得出父元素的高度被撑开了,但是还是多出了2px;
通过查阅资料,发现一个叫作[幽灵空白节点]的抽象概念(此概念并非权威,仅用于理解)
在HTML5文档声明下,块状元素内部的内联元素的行为表现,就好像块状元素内部还有一个(更有可能两个-前后)看不见摸不着没有宽度没有实体的空白节点,这个假想又似乎存在的空白节点,称之为“幽灵空白节点”。
既然这个节点看不见,决定用一个em
标签来假装,
em {
<!--为了查看元素的真实高度加此属性-->
display: inline-block;
font-style: normal;
}
<div>
<em>X</em>
<span class="title">大标题</span>
<span class="sub-title">小标题</span>
</div>
可以看到该元素的真实高度为21px,撑开了父元素高度
然后因为子元素会继承父元素的line-height
属性,将div
的line-height
属性设置为一个较小的值
div {
line-height: 5px;
}
可以看到该节点的真实高度变为5px,div
的高度也是正常的了;
四、解决办法
1、设置较小的line-height
属性,通常都会设置成0。
div {
line-height: 0;
}
em {
display: inline-block;
font-style: normal;
}
.title {
display: inline-block;
line-height: 20px;
font-size: 20px;
background: red;
}
.sub-title {
display: inline-block;
line-height: 20px;
font-size: 14px;
vertical-align: top;
background: yellow
}
2、 因为line-height
默认值为[数值],计算时跟font-size
有关,又因为font-size
是可以继承的。所以可以设置父元素font-size
为 0。
div {
font-size: 0;
}
em {
display: inline-block;
font-style: normal;
}
.title {
display: inline-block;
line-height: 20px;
font-size: 20px;
}
.sub-title {
display: inline-block;
line-height: 20px;
font-size: 14px;
vertical-align: top;
}
可以看到[幽灵节点]的宽高都是0,div的高度也是正常的。
五、line-height
的其他应用
1、多行文字的垂直居中
要实现高度不固定的文字垂直居中使用padding就好了。对于高度固定的div,里面文字单行或多行显示,字体大小有大有小的情况怎么办呢?方法之一就是借助于line-height
。
div {
width: 300px;
height: 150px;
line-height: 150px;
border: 1px dashed #ccc;
}
span {
font-size: 12px;
display: inline-block;
line-height: 1;
}
<div>
<span>多行文字的垂直居中多行文字的垂直居中多行文字的垂直居中多行文字的垂直居中</span>
</div>
2、图片的水平垂直居中
li {
display: inline-block;
width: 150px;
height: 150px;
line-height: 150px;
text-align: center;
border: 1px solid #ddd;
}
img {
vertical-align: middle;
}
<ul>
<li><img src="http://image.zhangxinxu.com/image/study/s/s128/mm1.jpg" /></li>
<li><img src="http://image.zhangxinxu.com/image/study/s/s128/mm2.jpg" /></li>
<li><img src="http://image.zhangxinxu.com/image/study/s/s128/mm3.jpg" /></li>
<li><img src="http://image.zhangxinxu.com/image/study/s/s128/mm4.jpg" /></li>
<li><img src="http://image.zhangxinxu.com/image/study/s/s128/mm5.jpg" /></li>
<li><img src="http://image.zhangxinxu.com/image/study/s/s128/mm6.jpg" /></li>
</ul>
六、总结
以上就是本人对行内布局以及line-height的一些思考总结。
另外也可以使用flex布局一把梭,就没这么多事了~。
参考