《CSS世界》笔记三:内联元素与对齐

jianqi 2019-06-28

上一篇:《CSS世界》笔记二:盒模型四大家族
下一篇:《CSS世界》笔记四:流的保护与破坏

写在前面

在页面布局中,内联元素的垂直对齐是比较常见和基础的布局需求,但是我们往往会因为垂直对齐中的1px,2px而头疼不已。在这一篇博客(《css世界》第五章)中,张大大从深层次解释了垂直对齐的原理,并为内联元素的垂直对齐提供了最佳实践。

一、基本概念

(1)基线(baseline):字母 x 的下边缘(线)就是基线

(2)x-height:小写字母 x 的高度,术语描述就是基线和等分线(mean line)(也称作中线,midline)之间的距离

《CSS世界》笔记三:内联元素与对齐

ascender height: 上行线高度
cap height: 大写字母高度
median: 中线
descender height: 下行线高度

(3)middle线vertical-align:middle; 中middle指的是基线往上1/2 x-height高度(近似垂直居中)

(4)单位ex:CSS中的一个相对单位,指的是小写字母 x 的高度
用法:不受字体和字号影响的内联元素的垂直居中对齐效果

.icon-arrow {
    display: inline-block;
    width: 20px;
    height: 1ex;
    background: url(arrow.png) no-repeat center;
}

二、行高line-height

对于非替换元素的纯内联元素,其可视高度完全由 line-height 决定,通俗的说,纯内联元素的可视高度不受padding、margin、border 属性的影响(这个我们在上一篇博客也有说明)

2.1 行距

一个公式:行距 = line-height - font-size

上下行距分配规则:当行距为偶数时,上下行距平分;当行距为基数时,上边距向上取整,下边距向下取整;因为绝大多数字体都是偏下的

《CSS世界》笔记三:内联元素与对齐

2.2 line-height实现居中

误区:并非是line-height=height实现了单行文本的居中,line-height单独作用即可实现

应用:利用line-height实现多行文本居中对齐

<div class="box">
    <div class="content">基于行高实现的...</div>
</div>

/* 近似居中对齐 */
.box {
    width: 280px;
    line-height: 120px;
    background-color: #f0f3f9;
    margin: auto;
}
.content {
    display: inline-block;
    line-height: 20px;
    margin: 0 20px;
    text-align: left;
    vertical-align: middle;
}

/* 绝对居中 */
.box {
    font-size: 0;
}
.box .content {
    font-size: initial;
}

原理:
近似居中:.box行高为120,.content行高为20,“幽灵空白节点”在.content前撑起了整个内容区域

绝对居中:在上面的基础上,由于middle(基线往上1/2 x-height高度)为近似居中,由于x-height受到font-size的影响,font-size为0时可理解为绝对居中

2.3 line-height的属性值

line-height 的默认值是 normal,还支持数值、百分比值以及长度值

默认值normal在不同字体下的解析不同,因此在实际开发中一般会重置line-height

重点

假设 font-size = 14px;

数值:line-height: 1.5; ==> line-height 计算值是 1.5*14px=21px

百分比值:line-height: 150%; ==> line-height 计算值是 150%*14px=21px

长度值:line-height:21px

乍一看,似乎 line-height:1.5、line-height:150%和 line-height:1.5em 这3种用法是一模一样的,最终的行高大小都是和 font-size计算值,但是,实际上,line-height:1.5和另外两个有一点儿不同,那就是继承细节有所差别如果使用数值作为 line-height 的属性值,那么所有的子元素继承的都是这个值;但是,如果使用百分比值或者长度值作为属性值,那么所有 的子元素继承的是最终的计算值

最佳实践:基本上各大站点都是使用数值作为全局的 line-height 值

三、vertical-align属性(重点)

vertical-align 作用的前提条件是:只能应用于内联元素以及display值为table-cell的元素,注意,浮动和绝对定位会让元素块状化也会使vertical-align失效

3.1 属性值

四类属性值:

  • 线类,如 baseline(默认值)、top、middle、bottom;
  • 文本类,如 text-top、text-bottom;
  • 上标下标类,如 sub、super;
  • 数值百分比类,如 20px、2em、20%等;
根据计算值的不同,相对于基线往上或往下偏移,到底是往上还是往下取决于vertical-align的计算值是正值还是负值,如果是负值,往下偏移,如果是正值,往上偏移
vertical-align:baseline 等同于 vertical-align:0

vertical-align的百分比:margin 和 padding 是相对于宽度计算的,line-height 是相对于 font-size 计算的,而这里的 vertical-align 属性的百分比值则是相对于 line-height 的计算值计算的

3.2 vertical-align相关问题及解决

(1)案例一:任意一个块级元素,里面若有图片,则块级元素高度基本上都要比图片的高度高

<div class="box">
    <img src="mm1.jpg">
</div>

.box {
    border: 1px solid #ccc;
}
.box > img {
    height: 96px;
}

《CSS世界》笔记三:内联元素与对齐

原因:间隙产生的三大元凶就是“幽灵空白节点”、line-heightvertical-align属性;图片前放置小写的x,会发现图片的基线是元素底部,与“幽灵空白节点”的基线(小写x下边缘)对齐;

解决方法

  1. 图片块状化:可以一口气干掉“幽灵空白节点”、line-heightvertical-align
  2. line-height:0;
  3. font-size: 0;
  4. 干掉基线对齐:vertical-align的值为top、middle、bottom中的任意一个都是可以的

(2)案例二:使用text-align: justify;实现文字两端对齐

text-align: justify;多用于文字排版,有一个非常重要的特性:不会对最后一行两端对齐,因此单行文本时若要对齐需要人为换行

补充text-align: justify;的用法案例:

<div class="form">
    <label for="name">姓名</label><input id="name" type="text"><br>
    <label for="tel">联系方式</label><input id="tel" type="text">
</div>

$font-size: 14px;
$line-height: 1.5;

.form {
    background-color: #eee;
    width: $font-size * 5 + 150px;
}
label {
    display: inline-block;
    text-align: justify;
    width: $font-size * 5;
    height: $font-size * $line-height;
    overflow: hidden;
    vertical-align: bottom;
    margin-right: 10px;
}
label:after {
    content: '';
    width: 100%;
    display: inline-block;
}

《CSS世界》笔记三:内联元素与对齐

(3)案例三:使用text-align: justify;实现列表两端对齐

为了让最后一行也两端对齐,需要使用占位元素实现换行

<div class="box">
    <img src="1.jpg" width="96">
    <img src="1.jpg" width="96">
    <img src="1.jpg" width="96">
    <img src="1.jpg" width="96">
    <i class="justify-fix"></i>
    <i class="justify-fix"></i>
    <i class="justify-fix"></i>
</div>

.box {
    text-align: justify;
}
.justify-fix {
    display: inline-block;
    width: 96px;
}

《CSS世界》笔记三:内联元素与对齐

此时,元素底部有很大的间隙。产生的原因无非是vertical-align,因此我们会设置line-height:0;,但是并没有真正解决问题,为什么?

一个 inline-block 元素,如果里面没有内联元素,或者overflow不是visible,则该元素的基线就是其 margin 底边缘;否则其基线就是元素里面最后一行内联元素的基线。
<span class="dib-baseline"></span>
<span class="dib-baseline">x-baseline</span>


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

实际展示如下图所示:
《CSS世界》笔记三:内联元素与对齐

最终解决:

  1. font-size: 0;
  2. line-height: 0; 且在占位元素中添加空格<i class="justify-fix">&nbsp;</i>

四、扩展案例

4.1 基于20px图标对齐最佳实践

一个 inline-block 元素,如果里面没有内联元素,或者 overflow 不是 visible, 则该元素的基线就是其 margin 底边缘;否则其基线就是元素里面最后一行内联元素的基线。

基于上面的理论,有下面几个要点:

  1. 图标高度和当前行高都是 20px
  2. 图标标签里面永远有字符,可以借助:before 或:after 伪元素生成一个空格字符轻松搞定
  3. 图标 CSS 不使用 overflow:hidden 保证基线为里面字符的基线,但是要让里面潜在的字符不可见
.icon {
    display: inline-block;
    width: 20px; height: 20px;
    background: url(sprite.png) no-repeat center;
    white-space: nowrap;
    letter-spacing: -1em;
    text-indent: -999em;
}
.icon:before {
    content: '\3000';
}

4.2 无兼容的水平垂直居中弹框

利用之前提到的绝对居中的知识vertical-align:middle; font-size:0;

<div class="container">
    <div class="dialog"></dialog>
</div>

.container {
    position: fixed;
    top: 0; right: 0; bottom: 0; left: 0;
    background-color: rgba(0,0,0,.5);
    text-align: center;
    font-size: 0;
    white-space: nowrap;
    overflow: auto;
}
.container:after {
    content: '';
    display: inline-block;
    height: 100%;
    vertical-align: middle;
}
.dialog {
    display: inline-block;
    vertical-align: middle;
    text-align: left;
    font-size: 14px;
    white-space: normal;
}

五、总结

  1. 内联元素各种线 & 行高计算及分配规则;
  2. 利用line-height如何实现多文本居中 & line-height 各属性值区别
  3. vertical-align取值对垂直对齐的影响及解决方式
  4. justify 实现文字两端对齐和列表两端对齐

上一篇:《CSS世界》笔记二:盒模型四大家族
下一篇:《CSS世界》笔记四:流的保护与破坏

相关推荐