前言

在PC时代,垂直居中就是一个会引起很多讨论的问题,例如经典问题:如何在任何容器里,让任意行数的元素都能垂直居中,相信很多同学对于这个问题还记忆尤深。如今移动端已经成为了我们的主要平台,随之而来的问题也更加复杂。

而作为大促前端,我们的问题更加复杂,我们需要兼容大量不同平台的手机,例如:安卓4.4系统、IOS8、IOS9等等远古手机。可能有同学很好奇为何还需要花费时间去兼容这些手机,原因很简单:数据支撑,京东大促的用户量级非常巨大,虽然这些手机用户占比很少,但是当用户基数达到一定数量时,即使占比很小,数量也是很可观的,对应而来的就是各种客诉,所以我们必须兼容这些手机。

本文将从以下场景讨论问题的解决方案。

主要诉求:

  • 文字小于12px在安卓和ios表现不同;
  • 文字在一定宽度下自适应,超过一定宽度需要截断;
  • 文字配图标或者其他元素;
  • 不使用JS,纯CSS;
  • dom节点只有2层,比如

    1
    <div><span>任何元素<span><span class="tag">内容</span></div>
  • 必须兼容IOS9及以下和安卓4.4.4,所以首先被排除的方法就是flex布局;

    PS. 本文不讨论PC下的展示效果

主要问题:

假如设计稿高度为28px,我们如果把行高写成28px,那么在IOS和安卓下,必然是会出bug的,相信实践过的朋友都知道,同样的行高,IOS下没什么问题,但是在安卓下,文字是偏上的,如图所示:

安卓下效果

经典问题了,怎么解决呢,根据网上的经验,都是建议使用flex布局的align-items来布局,但是这种布局不支持4.4.4的安卓手机,所以不行,同理grid也是不行。

方法一:table布局

我尝试使用了table来进行布局,如果不考虑截断的问题,是可行的,缺点是必须2层结构,否则无法实现文字截断的效果,效果如下:
table布局

代码如下:

1
<div class="word"><span>文字文字文字文字文字文字</span></div>

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
.word {
font-size: 10px;
background: red;
color: white;
display: inline-table;
padding: 0 10px;
table-layout: fixed;
width: 100px;
}
.word span {
display: table-cell;
height: 22px;
vertical-align: middle;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
PS:table布局同样适用于2行纯文字,但是无法截断。

方法二:line-height: normal

我们还可以使用line-height: normal的方法来实现,效果如下:
line-height:normal方法
代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
.word {
font-size: 10px;
background: red;
color: white;
display: inline-block;
padding: 3px 10px;
width: 100px;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
.word span {
line-height: normal;
}

缺点:必须多套一层结构

PS:line-height: normal的元素不能设置高度,只能使用padding或者margin来模拟高度

方法三:???

我们都知道,安卓下的文字是偏上的,所以我就把line-height加高了几个像素,奇迹发生了,安卓下居中了,IOS基本没变,绝了!
经过试验,line-height值需要比height值大2px即可,IOS对这个值的敏感度非常小,只要不大于这个值,就几乎不变。

安卓:
安卓
IOS:
IOS

1
2
3
4
5
6
7
8
9
10
11
12
13
14
<div class="word">文字文字文字文字文字文字</div>
.word {
font-size: 10px;
background: red;
color: white;
display: inline-block;
padding: 0 10px;
line-height: 24px;
height: 22px;
width: 100px;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}

这个方法的应用场景在哪呢,文字+icon+需要截断+自定义宽度,经过研究,我发现,这种情况下,如果不使用js或者hack,是不可能使用纯CSS的办法完美解决的,所以使用该方法,可以保证在所有安卓和IOS的差距保持在一个设计师可以接受的范围内。

效果如下:
安卓:
安卓
IOS:
ios
代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
.word {
display: inline-block;
border-radius: 4px;
color: #fff;
background: #E8220E;
text-align: left;
overflow: hidden;
font-size: 20px;
max-width: 180px;
white-space: nowrap;
vertical-align: top;
padding: 0 6px 0 6px;
height: 28px;
line-height: 32px;

&__pre {
display: inline-block;
vertical-align: top;
padding-right: 4px;
line-height: 30px;
}
&__text {
display: inline-block;
vertical-align: top;
width: calc(100% - 20px);
text-overflow: ellipsis;
white-space: nowrap;
overflow: hidden;
table-layout: fixed;
}
}

该方法使用了calc来计算整体宽度,来实现文字截断。这种方法能够兼容一行下的大部分情况,支持图标+文字文字+文字
缺点:IOS下可能还是会稍偏一点点,但是根据我们设计师的反馈,该误差可以接受,且该方法支持一行多个同时出现

总结

  • 根据实践,大部分情况下,方法3是覆盖面比较广的方法,line-height的值 > height的值即可;
  • 如果只有一行文字,建议使用line-height: normal;
  • 多行文字建议使用table布局,控制字数,因为无法截断;
感谢您的阅读,本文由 凹凸实验室 版权所有。如若转载,请注明出处:凹凸实验室(https://aotu.io/notes/2020/07/24/line-height-in-all-hardware/