多行文本省略近完美方案

原创文章,转载请注明出处。

背景

在项目需求开发时,由于文本内容长度的不确定性,经常会碰到文本内容超出的问题,通常这种情况,UI/UE都会要求我们将超出部分用省略号(...)来显示,这种做法基本上已经是一个业界共识了。然而,这么一个理所当然的效果,在前端却一直是一个难题。

希望

对于文本省略,由于CSS3的出现,出现了单行文本省略和多行文本省略的划分了(看完Can I Use,你会觉得这句话不合理,可,那又如何,哈哈(ಡωಡ)hiahiahia)。之所以这么说,那是因为CSS3定义了一个文本省略方案:

text-overflow: ellipsis | clip;

这在前端界可谓是相当腻害的进步,前端大拿、二拿、小拿们纷纷举起键盘YY:前端的巨轮势不可挡!

永远在那绿油油的田野上

不得不说,text-overflow的出现 ,确实让前端为之动容,多么美好,哪里还需要什么JS算字数啊。然而,真正用上text-overflow才发现,理想很美好,现实很骨感,这哥们只管单行文本溢出的省略,对于多行文本,却视而不见。

希望,依旧在那绿油油的田野上……

于是,文本省略从没有变成了两种:单行文本省略和多行文本省略。

单行文本省略

有,总比没有好

这是一条永恒的道理,好歹,解决单行文本省略时候,我们可以开开心心用CSS解决,而不用再去搞有的没的JS了。

用之前先看兼容

这是一条CSS规则。查Can I Use,这哥们的兼容性简直震憾人心啊:

text-overflow兼容性

牛不牛,服不服,连让你们诟病的IE都兼容到不可思议的地步了。(看到这里,我就想问,这哥们怎么到CSS3才被定义哈)

当然,并不是一条text-overflow: ellipsis;就可以实现文本省略。

无规矩,不成方圆

同样,text-overflow的使用,需要满足一些规矩

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

估计你们会发现,上述的规矩和你们认识的,或者在网上找到的教程不太一样。嗯嗯,的确如此,搜索各类教程基本给的说法是这样的:

  1. 块级元素
  2. overflow: hidden; // 也有说非visible
  3. width: 具体值,非auto
  4. white-space: nowrap;

其实,基本差不多,解释一下不一样的地方:

  1. overflow确实是非visible,但是,是计算值,并不是设定值。因为CSS里有个叫inherit的关键字。
  2. 元素宽度,而不是width,比如,max-width,以及厉害的flex布局也是可以的。
  3. white-space: pre; 也是可以的,这个属性的设定主要是为了不折行pre也是可以达到目的。

每个规则我就不一一给例子验证了,如果有问题,欢迎评论留言哈。这里就简单

举一个粟子

P.S. 图片来源于网络,但是没找到源头,若你们知道,麻烦告诉我,万分感谢!若是作者看到,觉得不可使用,告知于我,必及时删除之!
width规则里,我们用flex布局:

<div style="display: flex;">
  <div id="ellipsis-item" style="flex: 1;
    white-space: nowrap;
    overflow: hidden;
    text-overflow:ellipsis;
  ">这是一串很长很长很长很长很长很长很长很长很长很长很长很长很长很长很长很长很长很长很长很长的文字</div>
  <div style="flex: 1;">这是一串很长很长很长很长很长很长很长很长很长很长很长很长很长很长很长很长很长很长很长很长的文字</div>
</div>

把这坨下代码放到你的页面里,如果看不到...,缩小一下窗口,你会看到类似这样的情况:

flex布局无需width也可以实现...省略

很显然,代码里,我们并没有为#ellipsis-item元素声明width或是max-width属性,但是,省略依然见效。原因就是,设定flex属性后,元素就会被分配宽度计算值,从而使省略生效。在这个例子,宽度值是50%父元素宽度。

单行文本省略虽然不是本文的重点,但是也简单回顾一下,并完善些(可能不是完美)text-overflow的使用规则。

多行文本省略

也许有人会说,多行文本也有实现方法啊。确实,在Webkit系浏览器里还是有的:

line-clamp

OK,再回顾一下。

Webkit系解决方案

text-overflow一样,我们先看一下兼容性:

line-clamp兼容性

兼容性和text-overflow比起来,简单是惨不能睹,真是清一色Webkit,而且,还是-webkit-line-clamp,连正经的line-clamp都不是。为什么是-webkit-line-clamp呢?因为

  1. W3C没规范
  2. Webkit系自己YY的:所以带-webkit-
  3. 规则上,这哥们要转正,以后也得改哈

那就说下规则吧:

  1. display: -webkit-box | -webkit-inline-box;
  2. -webkit-box-orient: vertical | block-axis
  3. overflow: 计算值非visible
  4. -webkit-line-clamp: N; // 行数

可以看出来,-webkit-line-clamp依赖于box布局,而这家伙是最老的Flex布局方案,已经由新版的flex系替代,所以说,这哥们即使进W3C规范,估计也得改改了。

换句说,现在的写法,很可能未来不能再使用,结局估计是这两种:

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

所以,如果不是别无选择,还是不太建议使用。

好残酷,需求还要做,怎么办。。。JS搞起啊,算字数啊,加...

哈哈……

假装很完美的方案

哇靠,讲了那么多,总算回到标题了。。扯了这么多,感觉成了标题党,会不会被打哈。。
那些用JS算宽度算字数的方案我就不说了哈,你要是喜欢就自行到网上搜索呗。由于本人一贯的原则是:

能用CSS的,就不要用JS

所以,接下来这个方案,也必然是纯CSS方案了。另外,给你们点继续看下去的勇气:

  1. 纯CSS
  2. 高兼容性
  3. 适用于N行:不区分单行还是多行

首先,看个效果图:

多行文本截断效果图

是不是看起来超厉害,是不是以为是用的-webkit-line-clamp。。。然而,并不是哦。

其次,来理一下原理。

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

要验证我的说法是正确的,很简单,把你们经常用overflow: hidden;的写法改成overflow: auto;overflow: scroll;即可。

所以,我们的原理也是这样的,

拿个...盖到上面去

简单搞个图看下:


...盖示意图

从上图可以看到,实际上,我们要做的就是把粉色那个...,放在框的右下角,以隐藏右下角的最后那个字/内容,当我们把粉色改成白色,就会得到我们希望的...省略效果了:


...的最终效果

说到这里,...的方案很简单,可以使用一个特定的元素,也可以用::after伪元素。最后的代码类似这样的:

<div style="
    margin: 50px;
    width: 200px;
    height: 3em;
    line-height: 1.5;
    overflow: hidden;
    position:relative;outline:1px solid #ff9900
">这是一串很长的文字,现在开始哦。第二行文字在这里开始了
    <i style="
        position: absolute;
        bottom: 0;
        right: 0;
        width: 1.5em;
        padding-left: 2px;
        background-color: white;
    ">...</i>
</div>

到目前为止,一切似乎很顺利,网上随便一搜,都差不多是这个样子的。或许,你们有人已经在YY:你丫是在逗我吗,这谁不知道哈。

诚然,如果我说的方案就到此结束,还真是在逗你们了,但是,请认真继续看哈。

这个方案有一个很严重的问题,那就是:

理所当然地认为内容一定会溢出

是的,网上有些认真的人在写这个方案时候,还是会来个温馨提醒的,有的也会告诉你计算一下内容会不会溢出,如果是这样,干嘛不一开始就直接计算得了,还整了一个CSS+JS计算的方案哈。

当然,如果你可以百分百确定你的内容会溢出,到目前为止的方案已经足够。相反,你应该继续看下去。回到我刚才的截图里:


多行文本截断效果图

截图里可以看到,我们最终的方案是要保证:

当且仅当内容溢出时,显示...省略

究竟如何实现这个功能呢?回想一下我们这个...的方案原理,我们是拿...盖住右下角的内容来实现省略,其实,同样的道理,我们可以

拿个东西盖住...

是的,原理还是那个原理,只是换了谁盖谁。所以,前面那句话,我们就可以换成:

当且仅当内容溢出时,不盖住...

如何达到这个效果呢?要解释这个问题,我们来具象一下overflow: hidden;是什么样的一个效果。

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

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

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

至此,原理简单地抽象了一下。接下来,就是实现了,实现有很多方式,这里给出其中一种,具体怎么实现,看个人喜好吧,毕竟

思想是统一的,实现都是看人的

给出以下某个实现:

<style type="text/css">
    .ellipsis {
      margin: 20px;
    }

    .ellipsis {
      position: relative;
      width: 200px;
      max-height: 3em;
      line-height: 1.5;
      overflow: hidden;
      outline: 1px solid #ff9900;
    }
    .ellipsis::before {
      content: '...';
      position: absolute;
      z-index: 1;
      bottom: 0;
      right: 0;
      width: 1.5em;
      padding-left: 3px;
      box-sizing: border-box;
      background-color: white;
    }
    .ellipsis::after {
      content: '';
      display: inline-block;
      position: absolute;
      z-index: 2;
      width: 100%;
      height: 100%;
      background-color: white;
    }
  </style>
  <div class="ellipsis">这是一串很长的文字</div>
  <div class="ellipsis">这是一串很长的文字,现在开始哦。第二行文字在这</div>
  <div class="ellipsis">这是一串很长的文字,现在开始哦。第二行文字在这里开始了,从“里”字开始,就应该被...省略了。</div>

效果图这样的:


最终效果图

原理已经讲了,我就不再划实现的要点了,多动动脑,不会有害处的。

只是比较完美

虽然,最后的实现效果图上看,好像很完美的样子,但是,这个方案,同样有比较麻烦的地方,简单举例一下

  1. 中英文:纯英文或纯中文,比较简单,但是,如果右下角的字不能确定是中文还是英文时候,...的size和position的设定基本不会有一个完美值,有兴趣的可以自行测试
  2. 多选文本省略时,内容框的高度,要和N行高度保持一致,这是没有办法像浏览器处理那样,可以处理行上的省略的(overflow: hidden;只会截断)

其他的,我就不再举例了。对于1,可以考虑用渐变混合一下,弱化问题,对于2,就乖乖设定高度吧。

总之,这是一个还算比较完美的方案,但是,还是有其缺陷。如果有更好的方案,再做补充吧,也欢迎评论提供。

总结

本文总结了文本省略的方案,既有对浏览器支持方案的一些新见解,也分享了自己的解决方案,来划一下重点:

text-overflow使用规矩:

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

Webkit系列的多行文本省略:

  1. display: -webkit-box | -webkit-inline-box;
  2. -webkit-box-orient: vertical | block-axis
  3. overflow: 计算值非visible
  4. -webkit-line-clamp: N; // 行数

本人的方案:

  1. 在框右下角放个...,盖住右下角的内容
  2. 在内容尾,跟随一个mask,盖住上述的...,内容超出时,mask被推出,显示...

P.S. 原创文章,转载请注明出处。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 206,126评论 6 481
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 88,254评论 2 382
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 152,445评论 0 341
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 55,185评论 1 278
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 64,178评论 5 371
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,970评论 1 284
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,276评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,927评论 0 259
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 43,400评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,883评论 2 323
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,997评论 1 333
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,646评论 4 322
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,213评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,204评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,423评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,423评论 2 352
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,722评论 2 345

推荐阅读更多精彩内容

  • 问答题47 /72 常见浏览器兼容性问题与解决方案? 参考答案 (1)浏览器兼容问题一:不同浏览器的标签默认的外补...
    _Yfling阅读 13,728评论 1 92
  • 选择qi:是表达式 标签选择器 类选择器 属性选择器 继承属性: color,font,text-align,li...
    wzhiq896阅读 1,730评论 0 2
  • 选择qi:是表达式 标签选择器 类选择器 属性选择器 继承属性: color,font,text-align,li...
    love2013阅读 2,303评论 0 11
  • 年好过,月难熬,过日子比树上的叶子稠,不走的路还要走三遭。后半段的话实在不好理解,这是一位大哥的母亲说过的话,大哥...
    霖少爷阅读 271评论 0 1
  • 管理自己的时间,要从管理自己的想象力开始。以今天为例,有多少时间被浪费在了根本没有发生的事情上?早上醒来,明知时间...
    李德贤阅读 284评论 0 1