_前端-溢出文本显示省略号

前端技巧,大前端 2019-04-26 376 次浏览 次点赞

需求

  1. 省略号除了在最后,也可能处于前面、中间,或者两边
  2. 双击文本进行复制的时候,拿到的是全部的文本(不带省略号)(对搜索引擎良好,因为所有文本保留)
  3. 自适应,宽度足够的话不显示省略号
  4. 支持多行文本

技术预研

以下测试仅测试:chrome 73/ff 66/edge 18 不保证所有主流浏览器兼容

单行

省略号处于尾部

简单使用 text-overflow:ellipsis即可

当文本溢出包含元素时,显示省略符号来代表被修剪的文本

支持绝大部分浏览器(IE6+/xxxx

为了满足需求,还现需要进行其他css的设置,比如

  1. white-space: nowrap; //让文本单行显示
  2. overflow: hidden; // 隐藏溢出的文本
  3. width: 100%; // 网上说是兼容IE6,可不设,现在都9102年了

由于是隐藏溢出,所以双击复制文本的时候,拿到的是全部的文本(不带省略号)

省略号处于首部

在使用上述 省略号处于尾部 的前提下,

利用direction: rtl即可实现。

考虑到父元素宽度足够大的时候文本会靠右显示,还得在父元素上设置text-align: left;

<!DOCTYPE HTML>
<html>
<style type="text/css">
div {
  width:200px;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  direction: rtl;
  text-align: left;
}
</style>
</head>
<body>
  <div>我和五个优秀员工,分别是xxxx</div>
</body>
</html>

后记:发现应用 direction:rtl后,处于尾部的特殊字符将以从右往左的顺序排列在字符串前面,字符串前面的字符以从左往右的顺序显示再右边;

或者单独的数字串也会

比如

12-这是一段测试文本!@#$ 用于rtl后变成 $#@!这是一段测试文本-12 应用ellipsis后变成 ...测试文本-12

所以需要引入unicode-bidi,决定如何处理文档中的双书写方向文本

取值:

https://developer.mozilla.org/zh-CN/docs/Web/CSS/unicode-bidi

https://www.w3.org/TR/CSS2/visuren.html#propdef-unicode-bidi

normal:设置了 direction:rtl,则图片、按钮以及问号、加号之类的字符会从右往左显示,但是中文、英文字符还是从左往右显示

embed:作用在内联元素上,与normal的作用一样,但不受外部影响

bidi-override:所有的字符都按照统一的 direction 顺序排列

plaintext:不考虑父元素的双向状态,也不考虑 direction 属性的值。也就是会按我们的文本顺序显示

设置plaintext后,目前测试chrome是完美支持的。

但是!

ff 在设置该属性后,将不会再出现省略号

edge,ie 该属性只有前三种值,故首尾特殊字符位置不对

解决方案1: 左右加入特殊空白符:, 然后进行相对定位及移动;

这样保证了前面不会的特殊字符不会移动,同时unicode-bidi 不做处理。

缺点就是需要进行相对定位的一些兼容处理,同时复制出来会带个特殊空白符

解决方案2: 算法识别前后会造成偏移的字符串,进行切割

12-这是一段测试文本!@ 切割变成 12- 这是一段测试文本 !@

然后前后的字符串用 span(内联元素) 包装起来,并设置direction:ltr以及 unicode-bidi: embed;

embed 以 direction方向为准,故该字串里面字符显示会以ltr的顺序,即!@不会变成@!

那么首尾两个字符串为什么不会交换呢?

MDN 上对于 normal有句解释:对双向算法,此元素不提供额外的嵌入级别。对于内联元素,隐式的重新排序在元素的边界上起作用。

父级div为normal 则子元素为内联元素时,内联元素的排序规则还是从左往右显示

<!DOCTYPE HTML>
<html>
<style type="text/css">
div {
  text-align: left;
  width:250px;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  direction: rtl;
}
.t1 {
  direction: ltr;
  unicode-bidi: embed;
}
</style>
</head>
<body>
  <div><span class="t1">12-</span>这是一段测试文本<span class="t1">!@#$</span></div>
</body>
</html>

根据该思路我们就得到了方案3↓

解决方案3(推荐): 不分割,直接用再包装一个内联元素span,

<!DOCTYPE HTML>
<html>
<style type="text/css">
div {
  text-align: left;
  width:150px;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  direction: rtl;
}
span {
 direction: ltr;
 unicode-bidi: embed;
}
</style>
</head>
<body>
  <div><span>12-这是一段测试文本!@</span></div>
</body>
</html>

省略号位于两边

一般使用的场景是,我们搜索到某个关键字,然后要居住展示该关键字,左右两边超过边界的字符都显示省略号

思路1

切分为两个字符串,前面字符串包含主要内容,后面字符串利用省略号处于尾部来显示...

前面的字符串还是和 省略号处于首部 的做法一样,定宽块里面包一个行内元素

然后再取一个兄弟元素 span 包住剩余字符串;

最后用一个div包住两者,该div宽度为前串div宽度+16,同时应用 省略号处于尾部的样式

注意:为了自适应,前串的宽度定义为max-width: calc(100% - 14px);

当父div足够大时,前面的字串会先展示,然后开始展示后面的字串

demo:

<!DOCTYPE HTML>
<html>
<style type="text/css">
div {
  width: 200px;
  text-align: left;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.s1 {
  display:inline-block;
  text-align: left;
  max-width: calc(100% - 14px);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  direction: rtl;
}
.s1 span {
 direction: ltr;
 unicode-bidi: embed;
}
.s2 {
}

</style>
</head>
<body>
  <div class="div">
    <span class="s1"><span>12-这是一段测试文本一段测试文本!@</span></span
    ><span class="s2">看的到我吗?</span>
  </div>
</body>
</html>

显示效果为:

12-这是一段测试文本一段测试文本!@看的到我吗?

注意:行内元素之间会带一个空格;代码里写成一行就不会

其他一些技巧:https://css-tricks.com/fighting-the-space-between-inline-block-elements/

注意:ff复制的话需要ctrl+a全选才行

由于前面设置了overflow: hidden; (不应用的话是产生截断效果

可以看到后面的inline-block块会垂直偏下

基线问题的原因:

https://stackoverflow.com/questions/28887531/two-divs-same-line-why-overflow-hidden-causes-vertical-offset

https://www.w3.org/TR/CSS21/visudet.html#propdef-vertical-align

第一个字串设置vertical-align: text-bottom;即可

最终代码

<!DOCTYPE HTML>
<html>
<style type="text/css">
.dot3-between {
  width: 200px;
  text-align: left;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.dot3-between .s1 {
  display:inline-block;
  text-align: left;
  max-width: calc(100% - 14px);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  direction: rtl;
  vertical-align: text-bottom;
}
.dot3-between .s1 span {
 direction: ltr;
 unicode-bidi: embed;
}
.dot3-between .s2 {
}

</style>
</head>
<body>
  <div class="dot3-between">
    <span class="s1"><span>12-这是一段测试文本一段测试文本!@</span></span
    ><span class="s2">看的到我吗?</span>
  </div>
</body>
</html>

前串:str.substr(0,str.indexOf(pat))

思路2:

切分为两个字符串,各占50%,分别显示省略号

与上个效果不同,当父元素变大的时候,左右两边的字符会一起不断展示

策略1:当父元素足够大的时候,文字始终居中

要点在于前串设置width:50%;

<!DOCTYPE HTML>
<html>
<style type="text/css">
.div {
  width: 200px;
}
.s1 {
  display:inline-block;
  width:50%;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  direction: rtl;
}
.s1 span {
 direction: ltr;
 unicode-bidi: embed;
}
.s2 {
  width:50%;
  display:inline-block;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  text-align: left;
}

</style>
</head>
<body>
  <div class="div">
    <div class="s1"><span>12-这是一段测试文本!@1</span></div
    ><span class="s2">吱吱吱吱看的到我吗?</span>
  </div>
</body>
</html>

策略2:当父元素足够大的时候,文字始终居左

要点在于前串设置max-width:50%;

<!DOCTYPE HTML>
<html>
<style type="text/css">
.div {
  width: 200px;
}
.s1 {
  display:inline-block;
  max-width:50%;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  direction: rtl;
}
.s1 span {
 direction: ltr;
 unicode-bidi: embed;
}
.s2 {
  width:50%;
  display:inline-block;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  text-align: left;
}

</style>
</head>
<body>
  <div class="div">
    <div class="s1"><span>12-这是一段测试文本!@1</span></div
    ><span class="s2">吱吱吱吱看的到我吗?</span>
  </div>
</body>
</html>

字符串切割:

简单:str.substr(0,str.length/2)

复制: 统计字符宽度,取中值

字符宽度统计函数

注意:ff复制的话需要ctrl+a全选才行,且最后复制出来中间会有换行

省略号位于中间(或字串的某个位置)

思路1

参考 省略号位于两边-策略2

依旧需要对字符串进行切分

<!DOCTYPE HTML>
<html>
<style type="text/css">
.div {
  width: 200px;
}
.s1 {
  max-width:50%;
  display:inline-block;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  text-align: right;
}
.s2 {
  display:inline-block;
  max-width:50%;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  direction: rtl;
  text-align: left;
}
.s2 span {
 direction: ltr;
 unicode-bidi: embed;
}

</style>
</head>
<body>
  <div class="div">
    <div class="s1">12-这是一段测试文本!@1</div
    ><span class="s2"><span>吱吱吱吱看的到我吗?</span></span>
  </div>
</body>
</html>

中间显示的省略号一开始为......,后面可能为...(如果某个消失而某个还存在的话),最后消失

注意:ff和edge两个省略号中间会存在空白

注意:ff复制的时候会有换行

如果想保持只有一个...的话

未完待续。。。

多行

https://www.jianshu.com/p/07bcb00aa0ee

.multi-line-ellipsis {
  overflow: hidden;
  position: relative;
  text-align: justify;
  margin-right: -1em;
  padding-right: 1em;
  &::before{
    content: '...';
    position: absolute;
    right: 0;
    bottom: 0;
  }
  &::after {
    content: '';
    position: absolute;
    right: 0;
    width: 1em;
    height: 1em;
    margin-top: 0.2em;
    background: white;
  }
}
.block-with-text:before {
  content: '...';
  position: absolute;
  right: 0;
  bottom: 0;
}

未完待续。。。


本文由 GaHingZ 创作,采用 知识共享署名 3.0,可自由转载、引用,但需署名作者且注明文章出处。

如果对您有用,您的支持将鼓励我继续创作!