文本超出显示省略号的一个完美的方案

问题提出

之前做项目需求的时候呢。会经常碰到文本内容超出的问题。通常UI设计师会叫我们超出的话显示省略号。由于之前做这样的需求一直没有整理文本内容超出省略的方案。那么这篇博客就好好整理一下吧。

我们知道CSS3定义了一个文本省略方案text-overflow

MDN上是这么说的:

text-overflow 是一个css 属性,确定如何向用户发出未显示的溢出内容信号。它可以被剪切,显示一个省略号(…)或者显示一个自定义的字符串

1
text-overflow: ellipsis || clip ||  <string>

clip: 在内容区域的极限处截断文本。因此在字符串的中间可能在中间发生截断

ellipsis:用一个省略号(…)表示被截断的文本。这个省略号被添加在内容区域中。因此会减少显示文本。 如果是空间太少,那么省略号也会被截断。

<string>:用自定义字符串来表示被截断的文本。字符串内容将被添加在内容区域中,所以会减少显示出的文本。如果空间太小到连省略号都容纳不下,那么这个字符串也会被截断。

但是有一点要非常注意:

这个属性只对那些块级元素溢出的内容有效。但是必须与块级元素内联(inline)方向一致(举一个反例:内容在盒子的下方溢出。此时就不会生效)

这句话简单的理解就是:text-overflow 只管行文本溢出的省略。

于是文本省略分成了单行文本省略多行文本省略

单行文本省略

由以上我们知道text-overflow 是可以解决单行文本省略的。但是毕竟是css3出的属性, 我们先看看它的兼容性:

可以看出它的兼容性是非常好的。所以可以放心愉快的使用吧

当然了,不是只使用text-overflow:ellipsis 就可以实现文本省略的。

上头我们我们也说过:

这个属性只对那些块级元素溢出的内容有效。但是必须与块级元素内联(inline)方向一致(举一个反例:内容在盒子的下方溢出。此时就不会生效)

文本可能在以下情况下溢出:当其因为某种原因而无法换行(例如:设置了”white-space:nowrap”),或者一个单词因为太长而不能合理地被安置(fit)。

因此为了让text-overflow 能够生效。我们必须要在元素上添加几个属性和满足一些规则:

  • 块级元素
  • overflow:计算值非visible
  • 元素的宽度:超出时, 有一个确切的计算值
  • white-space:nowrap || pre

解释一下这几个规则:

  • overflow确实是非visible, 但是计算值并不是设定值, 因为css有个叫inhert的关键字
  • 元素宽度: 不是元素的width。max-width,以及flex 布局都是可以的。
  • white-space:pre也是可以的, 因为这个属性的设置主要就是为了不折行。

举个比较普遍的例子:

html:

1
2
3
<div class="name">
我的名字我的名字 我的名字 我的名字 我的名字
</div>

css:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
.name {

text-overflow: ellipsis;

/* 元素的宽度: 超出时, 有一个确切的计算值 */
/* 元素宽度: 不只可以是元素的width。max-width,以及flex 布局都是可以的。 */
width: 200px;

/* overflow:计算值非visible */
/* overflow确实是非visible, 但是计算值并不是设定值, 因为css有个叫inhert的关键字 */
overflow: hidden;

/* 不折行:white-space: pre || nowrap */
/* pre也是可以的, 因为这个属性的设置主要就是为了不折行。 */
white-space: pre;

}

结果:

本例子代码–>可点击查看

flex布局实现

html:

1
2
3
4
5
<div class="name">
<div class="ellipsis">
元素的宽度我使用flex布局也是可行的元素的宽度我使用flex布局也是可行的元素的宽度我使用flex布局也是可行的元素的宽度我使用flex布局也是可行的 元素的宽度我使用flex布局也是可行的元素的宽度我使用flex布局也是可行的元素的宽度我使用flex布局也是可行的元素的宽度我使用flex布局也是可行的 元素的宽度我使用flex布局也是可行的
</div>
</div>

css:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
.name {
displayflex;
}

.ellipsis {
text-overflow: ellipsis;

/* 元素的宽度: 超出时, 有一个确切的计算值 */
/* 元素宽度: 不只可以是元素的width。max-width,以及flex 布局都是可以的。 */
flex: 1;

/* overflow:计算值非visible */
/* overflow确实是非visible, 但是计算值并不是设定值, 因为css有个叫inhert的关键字 */
overflow: hidden;

/* 不折行:white-space: pre || nowrap */
/* pre也是可以的, 因为这个属性的设置主要就是为了不折行。 */
white-space: pre;
}

结果:

本例子代码—>可点击查看

其他的规则:

其余的其他设置我就不一一举例验证了。如果验证的时候有问题可以给我留言。

多行文本省略

使用 webkit-line-clamp

多行文本的省略,也有实现方法,但是只是针对webkit系浏览器**-webkit-line-clamp**

MDN上是这么说的:

–webkit-line-clamp: CSS属性 可以把块容器中的内容限定为指定的行数

–webkit-line-clamp 的语法:

1
-webkit-line-clamp: none || integer
  • none:表示值显示的内容不会被限制
  • integer: 这个值表示内容显示多少行之后会被限制,必须大于0

这个属性的规则:

  • -webkit-line-clamp 只有在 display 设置为**-webkit-box** 或者**-webkit-inline-box** 并且设置**-webkit-box-orient** 为vertical时才有效果
  • 在大部分情况下,也需要设置overflow属性为 hidden, 否则,里面的内容不会被裁减,并且在内容显示为指定行数后还会显示省略号(ellipsis ).

来看个例子:

html:

1
2
3
<div class="line">
我的名字我的名字我的名字我的名字我的名字 我的名字我的名字我的名字我的名字我的名字 我的名字我的名字我的名字我的名字我的名字 我的名字我的名字我的名字我的名字我的名字
</div>

css:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
.line {
width: 100px;

/* display 设置为-webkit-box 或者-webkit-inline-box */
display: -webkit-box;
/* -webkit-box-orient 必须设置为vertical */
-webkit-box-orient: vertical;
/* -webkit-line-clamp: none || integer */
-webkit-line-clamp: 3;
/* 在大部分情况下,也需要设置overflow属性为 `hidden`, 否则,里面的内容不会被裁减,并且在内容显示为指定行数后还会显示省略号(ellipsis ). */
overflow: hidden;

}

结果:

我们最后来看看 -webkit-line-clamp的兼容性:

兼容性和上头的 text-overflow 比起来,很惨。都是清一色的Webkit。 而且-wbkit-line-clamp 连 line-clamp 都不是。为什么是-webkit-line-clamp呢?因为

  1. W3C没规范
  2. Webkit系自己YY的:所以带-webkit-

而且由以上的规则我们知道-webkit-line-clamp 依赖与 box 布局,而且是最老的Flex布局方案,已经由最新版的代替flex替代。 如果这个这个属性要进W3C规范,就得改改了。 换一句话来说,现在的写法很有可能在未来不再使用。估计结局是这两种:

  • W3C收录规范:规则要改,因为box迟早会被废弃
  • W3C自己定义一个新的属性:整个废弃掉

结论:如果是不是别误选择,还是不建议使用

大多数网上的方案(css)

本着一种能使用css 实现的, 就不用js实现的想法。

在使用其他css 方式之前, 我们来看一下无论单行还是多行实现超出省略的原理:

不管是多行截断还是多行截断,实际上,浏览器并没有把超长的文字删除,而是在渲染的时候在块尾渲染一个”…”覆盖在上面。规则里面的overflow的计算值为非visible, 所以在视觉上是看不到的。

所以我们自己实现的方式的原理也是这样的(拿个… 盖到上面去

…的方案很简单,可以使用一个特定的元素, 也可以使用::after伪元素。我们可以看一个例子。

html:

1
2
3
<div class="line">
我的名字我的名字我的名字我的名字我的名字 我的名字我的名字我的名字我的名字我的名字 我的名字我的名字我的名字我的名字我的名字 我的名字我的名字我的名字我的名字我的名字
</div>

css:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
.line {
width:100px;
height:70px;
position: relative;
overflow: hidden;
}
.line::after {
content: "...";
position: absolute;
z-index: 1;
display: block;
background: #fff;
top: 42px;
right: 0;
}

结果:

此例子的代码–>可点击查看

现在, 一切看都挺不错的。顺便网上一搜, 都是这样的实现方案。

但是,这个方案存在一个很严重的问题:默认的认为内容一定会溢出

网上写这个方案的时候有些也会还有一些提示:计算一下内容会不会溢出。

额,这提示…还不入不提示。 如果需要 js 计算, 那好不如一开始就使用js的方式实现了呢。为啥还整出 css + js 的方案呢?

一个完美的方案

如果我们想实现 仅仅当内容溢出时, 显示…省略 这样的方案, 我们该如何做呢?

我们回想一下我们上头的方案,我们是拿”…“ 盖住了右下角的内容来实现的省略。其实, 同样的道理,我们可以 拿个东西盖住…

原理还是那个原理,只是换了谁盖谁,所以我们的实现方案可以是:当且仅当内容溢出时,不盖住…

但是, 我们如何使用css 实现这样的效果呢? 我们怎么知道什么时候内容溢出呢?

我们抽象理解一下这个方案:

  • 假设我们的内容是用一个数组存储的,我们的内容框只能承载20个字,也就是说,我们的数组length一旦大于20,index >= 20的元素就不能再显示了。

  • 现在,我们的数组是空的,我们给它丢个字(假设为:略)进去,使用栈方法,从头往里一直丢字(unshift(‘X’),X为某个字),那第一次丢进去的“略”字,就会被一直往后推,直到它被推到20的位置,“略”字就“不再显示”了。

原理:

...的覆盖,我们也用“推”的方法,想象一下,我们找个东西,把它盖到...上,这就是第一个字“略”,然后,我们一直在这个东西前面添加我们的文本内容,当我们把这个东西推到框外时,就意味着我们的内容溢出了,...需要显示。而在此之前,由于东西一直处在index < 20,所以,它就一直存在,一直盖住...,这就是:内容未溢出,不显示...

原理讲完了, 我们来简单实现一下这个方案,这个原理实现的方案很多, 看自己怎么写。看个例子:

html:

1
2
3
<div class="line">
手动添加这里的内容看结果哦 手动添加这里的内容看结果哦 手动添加这里的内容看结果哦 手动添加这里的内容看结果哦
</div>

css:

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
.line {
width: 150px;
height: 90px;
border: 1px solid #000;
overflow: hidden;
word-break: break-all;
position: relative;
}
/* 实现省略号 */
.line::before {
content: "...";
position: absolute;
background: #fff;
width: 20px;
right:0;
top: 70px;
}
/* 盖住...的内容 */
.line::after {
content: " ";
position: absolute;
width: 100%;
height: 100%;
background: white;
}

结果: 当内容没有超出的时候, 省略号(…)被盖住。当内容超出时。省略号(…)不被盖住

这个例子的代码—> 点击查看

这是我认为的比较完美的纯css 方案了

文章作者: 舒小琦
文章链接: https://shuliqi.github.io/2020/06/22/文本超出显示省略号的一个完美的方案/
版权声明: 本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自 舒小琦的Blog