在前端领域,谈到文本截断,很多人第一反应可能是text-overflow: ellipsis
这行代码。我也一样,而且这是我心目中最为简单和优雅的实现方式了,不过,现实之中总能遇到一些意外状况。比如,多行文本的截断怎么操作?
如果说这还有现成的属性可以用,那更麻烦一点的,如果截断操作不在DOM中,比如在canvas中,怎么办?
如果上面这两个问题你脑海中已经有答案了,那你或许不用浪费时间看下去了,为师已经没什么可教的了。否则,看完本文,相信你能学到一点新东西。
我最近在使用cytoscape.js画图的时候,就遇到了这样的场景,需要在canvas中做多行文本的截断,尽管这个库已经支持了不少样式操作,但是很遗憾,并不支持多行文本截断。不过这个需求并非不可实现的,借助canvas的measureTextAPI,再结合javascript,还是可以实现的。
单行文本截断
在具体描述我的解决方案之前,先复习和回顾一下CSS实现的文本截断及其特点。
要实现单行文本截断,text-overflow: ellipsis
一行代码是不够的,比如结合其他几个属性一起使用,其中包括:
overflow: hidden;
这是为了让溢出的部分隐藏的,不添加这个属性的话,截断的省略号是看不到的white-space: nowrap;
这会强制不让文本换行,因为text-overflow
只能操作单行文本width
或max-width
用于限制宽度,否则浏览器也不知道什么时候该截断。不过这个属性并不一定必须加在目标元素身上,其父元素或祖先元素有也可以,只要该元素的宽度被限制就够了。display
这个属性也不是必须的,因为宽度对于行内元素是没用的,所以如果目标元素是span
的话,需要这个属性将其变为非行内元素,例如display: inline-block;
一段完整的CSS代码可能是这样的
|
|
被截断的元素还有几个特点:
- 文本省略是纯样式操作,完整的文本仍然在DOM中,当用鼠标三击选中整句话,然后复制,得到的是完整文本。
…
这个符号,是Unicode字符U+2026,并非三个英文句号,且这个符号是无法选中的。- 不管是
max-width
还是width
,只要文本溢出省略号出现,那么这一个元素的宽度就是指定的数值。这里举个例子解释下,假如max-width
是200px,截断后的文本是192px,省略符号是6px,按理说元素应该是198px,但是实际上会有2px的空白,元素会被填充到200px。
多行文本截断
先上代码
|
|
这个没什么好说的了,固定用法,display: -webkit-box;
-webkit-line-clamp: 3;
-webkit-box-orient: vertical;
三个属性是结合使用的,缺一不可,其中-webkit-line-clamp: 3;
是指定的是行数,根据需要填写。
单行文本截断元素的几个特点也同样应用于此处。另外,尽管box-orient
属性已经被废弃,各种标红不建议使用,但事实是并没有一个能够替代的属性出现,且这个被废弃的属性仍然被各大浏览器广泛支持。
使用measureText API进行文本截断
measureText,就按照字面意思理解,用来测量文本,这里还是先上代码,再来解释
|
|
meatureText的用法很简单,只需要通过canvas的Context2D对象进行调用即可,这里有一个需要注意的是字体,其默认值为10px sans-serif
,需要手动修改,可以不必像我一样利用getComputedStyle
来获取,直接用字符串16px Helvetica
也是一样的。函数接下来的部分就没什么好说的了,用了一个二分法来查找截断位置的索引,最后获取到截断后的文本即可。这个函数只是用来演示这个思路,实际使用的时候还有优化空间。
有几个注意事项,对应前面CSS截断的几个特点:
- DOM中的文本就是看到的文本,包括那三个点,如果要做到全选时复制完整文本则需要添加额外的copy事件完成
- 要想省略符号不被选中,可以结合伪元素做到
- 其宽度就是实际宽度,要想做到和CSS一样的空白补齐就设置元素的
width
样式属性
最后,我将上述代码整合到了codepen中,你可以点开自己动手玩一玩
See the Pen 文本截断 by eyebrowkang (@eyebrowkang) on CodePen.
总结
本篇文章梳理了纯CSS的单行和多行文本截断,然后讲解了我使用javascript完成类似效果的一种思路,后续如果遇到其他文本截断的方法我也会补充进来。