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

技术预研

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

单行

省略号处于尾部

简单使用 text-overflow:ellipsis
即可
当文本溢出包含元素时,显示省略符号来代表被修剪的文本
支持绝大部分浏览器(IE6+/xxxx
为了满足需求,还现需要进行其他css的设置,比如

white-space: nowrap;
overflow: hidden;
width: 100%;

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

省略号处于首部

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

利用 direction: rtl
即可实现。

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



div {
  width:200px;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  direction: rtl;
  text-align: left;
}



  
我和五个优秀员工,分别是xxxx

后记:发现应用 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 则子元素为内联元素时,内联元素的排序规则还是从左往右显示



div {
  text-align: left;
  width:250px;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  direction: rtl;
}
.t1 {
  direction: ltr;
  unicode-bidi: embed;
}



  
12-这是一段测试文本!@#$

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

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



div {
  text-align: left;
  width:150px;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  direction: rtl;
}
span {
 direction: ltr;
 unicode-bidi: embed;
}



  
12-这是一段测试文本!@

省略号位于两边

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

思路1

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

前面的字符串还是和 省略号处于首部
的做法一样,定宽块里面包一个行内元素
然后再取一个兄弟元素 span 包住剩余字符串;

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

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

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



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 {
}




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

显示效果为:


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;
即可
最终代码



.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 {
}




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

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

思路2:
切分为两个字符串,各占50%,分别显示省略号
与上个效果不同,当父元素变大的时候,左右两边的字符会一起不断展示
策略1:当父元素足够大的时候,文字始终居中

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



.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;
}




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

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

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



.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;
}




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

字符串切割:

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

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

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

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

思路1

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

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



.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;
}




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

中间显示的省略号一开始为 ......
,后面可能为 ...
(如果某个消失而某个还存在的话),最后消失
注意:ff和edge两个省略号中间会存在空白
注意:ff复制的时候会有换行
如果想保持只有一个…的话
未完待续。。。