杂谈 height, line-height, display, vertical-align
先声明一下,测试环境为 IE7+ , Chrome, Firefox, 不爱测那么多浏览器。。。
坑爹的行内元素
HTML:
<div> <span>文字</span> </div>
CSS:
body { font-family: '宋体'; font-size: 12px; }
这种情况下,span 和 div 都是由文字撑开高度,但是高度各有不同。
div: 所有浏览器都是height: 12px
span: IE7 IE8 Chrome 是height: 12px, IE9 IE10 Firefox 是height: 14px
第一个例子就这么坑爹,可见这里的水多深。我们先来看line-height,在Firefox 是line-height: 15px,而IE9/10 是 line-height: normal;
也许你会说这就是原因所在,于是设置了以下这段CSS
body { font-family: '宋体'; font-size: 12px; line-height: 1em; }
很不幸,没用!虽然设置line-height后,各个浏览器的 line-height 是一样了,但是高度还是不同。
再来看display
span { display: block; }
好吧,这样就相同了,设置成 inline-block 也是可以的。有这样的问题还要行内元素干嘛,inline 全部设置成 inline-block 算了
垂直对齐
HTML:
<div> <span>文字</span> </div>
CSS:
span { display: inline-block; *display: inline; *zoom: 1; } body { font-family: '宋体'; font-size: 12px; line-height: 1em; } div { border: 1px solid red; height: 18px; } span { border: 1px solid blue; }
所有浏览器表现一致
这也是垂直对齐最简单的情况,如果出现文字 + 图标,特别是图标的高度和文字不同时,情况会复杂很多。
文字 + 图标
我们先来看图标比文字高度小的情况:
HTML:
<div> <span>文字<button></button></span> </div>
CSS:
span { display: inline-block; *display: inline; *zoom: 1; } body { font-family: '宋体'; font-size: 12px; line-height: 1em; } div { border: 1px solid red; height: 18px; } span { border: 1px solid blue; vertical-align: top; } button { border: none; margin: 0; padding: 0; background-color: green; width: 10px; height: 10px; vertical-align: baseline; }
因为大多css reset 喜欢设置 vertical-align: baseline,所以这里加了这么一句。渲染结果主要有以下两种:
IE8+, Chrome
IE7, Firefox
第二个结果比较费解,第一它以底部对齐,第二它撑大了高度,span不再是12px,而是又变成了第一个问题中的14px。
看来baseline这种对齐方式很不靠谱,所以我决定采用 top(text-top 和 text-bottom 在 Firefox 中有点问题,span 高度会变为13px,所以不用这两个),这回所有浏览器都表现一致了
如果想实现垂直居中对齐,也许有些人会用vertical-align: middle,但是这方式特别不靠谱,就像刚才我们设置成 baseline 一样,各个浏览器表现还不一样,所以我的解决方法是:
1. vertical-align: top; 先把元素定到顶部
2. position: relative; top: 1px 进行位移调整
文本垂直居中
刚才说了图标的垂直居中,现在来看文本,一般的做法是 height 和 line-height 设置成相同的值
<div style="height: 20px;line-height: 20px">文字</div>
这样肯定能垂直居中,但是如果里面不是文本节点,而是套了一个行内元素呢?
<div style="height: 20px;line-height: 20px"><span>文字</span></div>
如果 span 是 display: inline; 那么还是会居中。
大家都知道 IE 有个 hasLayout,这里会有什么影响呢?
line-height 属性具有继承性,所以 span 的 line-height 也是 20px。
当 span 是行内元素,或者对于IE来说,是不具有 hasLayout 的时候,span 的高度小于 div,垂直居中表现完美。
当 span 是 inline-block,或者对于IE来说,具有 hasLayout 的时候,span 继承自父元素的 line-height 就会发挥作用,即撑满父容器。
对于IE8+ 和其他标准浏览器来说,只要这个盒模型的高度比 div 小,那么垂直居中还是正常的;如果比 div 大,就会顶部对齐
但对于IE7,不管这个盒模型多大,直接就顶部对齐了
所以呢,要套行内元素时,它只能是 display: inline (IE 下别触发hasLayout)
接着这个话题再复杂化一点,如果文本的实际高度,即一般都是12px,小于 height 和 line-height 的值,这时再加入一个图标,这时的垂直对齐是怎样的呢?
HTML:
<span>文字<button></button></span>
CSS:
span { display: inline-block; *display: inline; *zoom: 1; } body { font-family: '宋体'; font-size: 12px; line-height: 1em; } span { border: 1px solid blue; height: 20px; line-height: 20px; } button { border: none; margin: 0; padding: 0; background-color: green; width: 10px; height: 10px; vertical-align: top; }
结果分两种
IE8+, Chrome, Firefox
IE7
IE7这种行为真是匪夷所思,居然和 text-top 一样,但是如果把HTML改成下面这样就正常了
<span><span>文字</span><button></button></span>
这样看,IE好像把文本节点当作对齐的标准了。
所以如果有垂直对齐的需求,特别是 文本节点 + 行内元素 的组合,一定要给文本节点套一个 display: inline-block( IE 下触发hasLayout) 的行内元素,这样才能保证兼容性