多行超出尾部展示省略号

超出两行则末尾展示省略号

经常有需求一段文字展示时,单行超出自动折行,超出两行则末尾展示省略号。
css写单行超出显示省略号,可以复习下,这个很常用。

width: 3rem;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;

这种两行的文字,用纯css截取,移动端下载也ok了,iOS的我测了ok,安卓的只测试了小米,魅族,三星的部分机型,是否很符合规范大家可以去查查文档之类的,但是效果确实实现了啊,代码如下:

overflow: hidden;
text-overflow: ellipsis;
display: box;
display: -webkit-box;
-webkit-line-clamp: 2;
-webkit-box-orient: vertical;

进化

这两天抽时间做了一个退化处理,就是支持-webkit-box属性的浏览器中采用css来控制,不支持这一属性的浏览器如IE9以上、火狐浏览器,则使用JS动态计算的方法裁剪文本,在文本末未追加省略号(…)。在这个过程中,出乎意外的发现了chrome浏览器的一个bug,版本 55.0.2883.87 m.

展示bug

你可以试试下面的代码,在hover的时候,尾部的省略号…不会跟着变色。

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<style>
 div{
  color: blue;
 }
span{
    overflow:hidden;
    text-overflow: ellipsis;
    display: -webkit-box;
    -webkit-line-clamp: 2;
    -webkit-box-orient: vertical;
    width: 100px;
    color: blue;
font-family: 微软雅黑, "Microsoft YaHei";
}
span:hover{
    color: red;
}
</style>
</head>
<body>
<div>
    <a href="www.baidu.com"><span>测试测试测试试1测试111试</span></a>
</div>
</body>
</html>

是不是很神奇,这是chrome 浏览器的一个bug。居然能找到浏览器的bug,真是很开心。
这个bug的复现条件是文本内容不能多,不能少,刚好在显示省略号的边界。最好的衡量方法是更换字体时用粗体会出现省略号,用宋体则不会展示省略号,那么就可以复现了。

解决方案

已经向chrome反馈了这个问题,等待更新。

说说我的退化方案吧

需要处理的难题是如何判断文本超出设定的显示范围,比如设定展示2行,那么怎么判断超出了两行呢?
需要知道一个两个dom函数:getComputedStyle 和currentStyle。这两个函数都是获取dom节点渲染后计算出来的属性,也就对应于computed attribute.
其中:getComputedStyle兼容IE9+,火狐和chrome,currentStyle适用于ie8及以下
处理的方法就是判断节点的渲染后的高度是不是超出了行高乘以行数,超出了则是需要裁剪字数。裁剪字数采用了一个近似方程:
裁剪后的字数 = 当前字数 展示的行数 行高 / 渲染后展示的高度
ps: 注意有个坑,就是currentStyle拿到的高度始终是auto,而在ie9可以通过拿父元素的高度的方式拿到

代码如下:

if (!document.getElementsByClassName) {
    document.getElementsByClassName = function (className, element) {
        var children = (element || document).getElementsByTagName('*');
        var elements = new Array();
        for (var i = 0; i < children.length; i++) {
            var child = children[i];
            var classNames = child.className.split(' ');
            for (var j = 0; j < classNames.length; j++) {
                if (classNames[j] == className) {
                    elements.push(child);
                    break;
                }
            }
        }
        return elements;
    };
}
//获取元素计算后展示的style
function getStyle(obj, attr) {
    return getComputedStyle(obj) ? getComputedStyle(obj)[attr] : obj.currentStyle[attr];
}
var _tempLineH = 0;
var _tempHeight = 0;
for (var j = 2; j < 5; j++) {
    var _cateNavBoxList = document.getElementsByClassName('f-' + j + 'lines');
    if (!_cateNavBoxList.length) continue;
    for (var i = 0; i < _cateNavBoxList.length; i++) {
        var item = _cateNavBoxList[i];
        _tempLineH = parseInt(getStyle(item, "lineHeight"));
        if (getStyle(item, "height") == "auto") {
            item.parentElement.style.height = "auto";
            _tempHeight = parseInt(getStyle(item.parentElement, "height"));
        } else {
            _tempHeight = parseInt(getStyle(item, "height"));
        }
        if (_tempHeight > j * _tempLineH) {
            item.innerText = item.innerText.substr(0, item.innerText.length * j * _tempLineH / _tempHeight - 1) + "...";
        }
    }
}

改进篇

由于上面的方法在截取字数的时候,算法比较粗糙,只是简单地计算比例关系。这里做了改进。上面算法最好的情况的是正好字数刚刚满;最差的情况是最后一行只能显示寥寥无几的几个文字加上…,这显然是不是我们的追求,于是乎可以改进一下。其实改进很简单,在上面算法的基础上,计算出来裁剪字数之后不断增加字数,当渲染后的高度刚好超过需要的行数的高度时候,这时的字数就是需要截取的准确字数。
代码如下:

//解决IE8之类不支持getElementsByClassName
if (!document.getElementsByClassName) {
    document.getElementsByClassName = function (className, element) {
        var children = (element || document).getElementsByTagName('*');
        var elements = new Array();
        for (var i = 0; i < children.length; i++) {
            var child = children[i];
            var classNames = child.className.split(' ');
            for (var j = 0; j < classNames.length; j++) {
                if (classNames[j] == className) {
                    elements.push(child);
                    break;
                }
            }
        }
        return elements;
    };
}
//获取元素计算后展示的style
function getStyle(obj, attr) {
    return getComputedStyle(obj) ? getComputedStyle(obj)[attr] : obj.currentStyle[attr];
}
//获取元素计算后展示的高度
function getHeight(item) {
    if (getStyle(item, "height") == "auto") {
        item.parentElement.style.height = "auto";
        return parseInt(getStyle(item.parentElement, "height"));
    } else {
        return parseInt(getStyle(item, "height"));
    }
}
var _tempLineH = 0;
var _tempHeight = 0;
for (var j = 2; j < 5; j++) {
    var _cateNavBoxList = document.getElementsByClassName(('f-' + j + 'lines'), document.body);
    if (!_cateNavBoxList.length) continue;
    for (var i = 0; i < _cateNavBoxList.length; i++) {
        var item = _cateNavBoxList[i];
        _tempLineH = parseInt(getStyle(item, "lineHeight"));
        _tempHeight = getHeight(item);
        if (_tempHeight > j * _tempLineH) {
            var leng = item.innerText.length * j * _tempLineH / _tempHeight - 1;
            var _tempText = item.innerText;
            item.innerText = _tempText.substr(0, leng);
            _tempHeight = getHeight(item);
            var k=0;
            while (_tempHeight <= j * _tempLineH) {
                k++;
                item.innerText = _tempText.substr(0, leng + k);
                _tempHeight = getHeight(item);
            }
            item.innerText = _tempText.substr(0, item.innerText.length - 3)+"...";
        }
    }
}

谢谢!



请遵守《互联网环境法规》文明发言,欢迎讨论问题
扫码反馈

扫一扫,反馈当前页面

咨询反馈
扫码关注
返回顶部