溢出文本显示省略号,关于text-overflow:ellipsis的那些事

溢出文本显示省略号,关于text-overflow:ellipsis的那些事
这个标题其实已经是一个老生常谈的问题了。很多时候,比如网站最基本的文章列表,标题会很长,而显示列表的区域宽度却没有这么宽,这时候最正常的做法就是让超出宽度的部分文字用省略号(…)来表示。通常做法是网站后台程序截取一定的字符然后输出到前台显示或者前台用javascript截取一定的字符,但是通过控制字数来截取的话还是存在一个大问题的,因为中文和英文的字符宽度问题,这个字数不好控制,而且通用性较差。那么有没有更好的方法呢,比如直接用CSS来解决的,当然是有的。

text-overflow是一个比较特殊的属性,W3C早前的文档中目前的文档中没有包含text-overflow属性,FML!)对其的定义是:

Name: text-overflow-mode
Value: clip | ellipsis | ellipsis-word

clip :  不显示省略标记(…),而是简单的裁切
ellipsis :  当对象内文本溢出时显示省略标记(…),省略标记插入的位置是最后一个字符。
ellipsis-word :  当对象内文本溢出时显示省略标记(…),省略标记插入的位置是最后一个词(word)。

至于为什么一开始我说text-overflow是一个比较特殊的样式呢?因为我们可以用它代替我们通常所用的标题截取函数,而且这样做对搜索引擎更加友好,如:标题文件有50个汉字,而我们的列表可能只有300px的宽度。如果用标题截取函数,则标题不是完整的,如果我们用CSS样式text-overflow:ellipsis,输出的标题是完整的,只是受容器大小的局限不显示出来罢了(表现上是超出部分显示省略标记…)。

text-overflow: ellipsis属性仅是注解,当文本溢出时是否显示省略标记。并不具备其它的样式属性定义。我们想要实现溢出时产生省略号的效果。还必须定义:强制文本在一行内显示(white-space:nowrap)及溢出内容为隐藏(overflow:hidden)。只有这样才能实现溢出文本显示省略号的效果。Via.

那么,如果我们要给p标签定义text-overflow:ellipsis就可以这么写:

p {
      white-space: nowrap;
      width: 100%;                  /* IE6 需要定义宽度 */
      overflow: hidden;             
 
      -o-text-overflow: ellipsis;    /* Opera */
      text-overflow:    ellipsis;    /* IE, Safari (WebKit) */
   }

使用样式前:

我是一段测试文字,请分别用IE,Safari,chrome,opera浏览器查看我哦!

使用样式后:

我是一段加长过的测试文字,请分别用IE,Safari,chrome,opera浏览器查看我哦!哈哈哈,看到省略号了么?

浏览器兼容状况

Browser Lowest Version Support of
Internet Explorer 6.0 text-overflow
Firefox (Gecko)
Opera 9.0 -o-text-overflow
Safari (WebKit) 1.3 (312.3) text-overflow

OH,FML!Firefox不支持这个属性!这回,Firefox你也太另类了吧!还有别的办法么,当然有,方法还挺多的。
比如Mozilla developer center推荐的-moz-binding CSS属性。Mozilla developer center给出的理由是text-overflow没有W3C的规范…但是因为Firefox支持XUL,一种XML的用户界面语言。并且Firefox还支持XBL,一种XML绑定语言,这样我们就可以使用Mozilla developer center推荐的-moz-binding CSS属性来绑定XUL里的ellipsis属性了。

1.XUL方式

首先,我们创建XUL,它应该被保存为ellipsis.xml:

<?xml version="1.0"?>  
<bindings   
  xmlns="http://www.mozilla.org/xbl"  
  xmlns:xbl="http://www.mozilla.org/xbl"  
  xmlns:xul="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"  
>  
    <binding id="ellipsis">  
        <content>  
            <xul:window>  
                <xul:description crop="end" xbl:inherits="value=xbl:text"><children/></xul:description>  
            </xul:window>  
        </content>  
    </binding>  
</bindings>

然后我们需要把这个xml文件放到一个目录,原来的css需要加一条,变成这样

p {
      white-space: nowrap;
      width: 100%;                  /* IE6 需要定义宽度 */
      overflow: hidden;             
 
      -o-text-overflow: ellipsis;    /* Opera */
      text-overflow:    ellipsis;    /* IE, Safari (WebKit) */
      -moz-binding: url('ellipsis.xml#ellipsis');    /* Firefox */
   }

虽然Firefox通过XUL的方式实现了ellipsis,但是还是需要注意以下这些问题:
1.经过XUL处理过的文本你将不能被选中,按理说-moz-user-select: text; 属性将允许文本被选中,但是我没有试验成功。
2.如果你给父元素绑定了XUL,那么子元素的内容将变得不可见。例如:

It is a longhaha long long long long text!

如果你只是给p节点绑定了XUL,那么在Firefox下你将看不到haha这个内容。
它的源代码实际上是:

<p>It is a long<em> haha</em> long long long long text!</p>

参考资料:

http://www.w3.org/TR/2003/CR-css3-text-20030514/
http://www.quirksmode.org/css/contents.html
https://bugzilla.mozilla.org/show_bug.cgi?id=312156
https://developer.mozilla.org/En/XUL
https://developer.mozilla.org/En/XUL/Description
http://www.rikkertkoppes.com/thoughts/2008/6/
http://www.w3.org/TR/xbl/
http://www.w3.org/TR/css3-text/

2.Javascript方式

既然XUL无法完美解决Firefox下文字溢出显示…,那么我们就求助javascript吧,当然,并不是古老的截取一定数目的字符来实现。
这里以jQuery为例,代码如下:

(function($) {
	$.fn.ellipsis = function(enableUpdating){
		var s = document.documentElement.style;
		if (!('textOverflow' in s || 'OTextOverflow' in s)) {
			return this.each(function(){
				var el = $(this);
				if(el.css("overflow") == "hidden"){
					var originalText = el.html();
					var w = el.width();
 
					var t = $(this.cloneNode(true)).hide().css({
                        'position': 'absolute',
                        'width': 'auto',
                        'overflow': 'visible',
                        'max-width': 'inherit'
                    });
					el.after(t);
 
					var text = originalText;
					while(text.length > 0 && t.width() > el.width()){
						text = text.substr(0, text.length - 1);
						t.html(text + "...");
					}
					el.html(t.html());
 
					t.remove();
 
					if(enableUpdating == true){
						var oldW = el.width();
						setInterval(function(){
							if(el.width() != oldW){
								oldW = el.width();
								el.html(originalText);
								el.ellipsis();
							}
						}, 200);
					}
				}
			});
		} else return this;
	};
})(jQuery);

这段js的原理很简单,就是通过不断的比较宽度值,然后逐个缩短字符宽度,当最后宽度合适的时候,停止循环,就实现了文字溢出显示…的效果。
这段js还需要一段css来配合。

.overflow {
	text-overflow: ellipsis;
	-o-text-overflow: ellipsis;
	white-space: nowrap;
	overflow: hidden;
}

js里有个判断就是当样式里出现text-overflow或者-o-text-overflow的时候,便不会执行这段js。因为支持这两个属性的浏览器可以自己实现ellipsis效果。

这两种方法都可以实现Firefox下ellipsis的效果,如何取舍使用,具体还得根据你要运用到的项目的具体情况来具体分析,XUL实现的方法的不足之处在以上已经很详尽地列举了,如果你可以避免或者说这些无关你项目的大问题,那么XUL不失一个好方法。

至于其他的一些方法你可能在网上也有看到,比如用:after伪类来实现等,个人不推荐,所以我这里也不细说了,如果你有更好的方法,也希望能与我分享,谢谢观看!

2011.09.28更新:Firefox7已经支持text-overflow:ellipsis了,enjoy it!

68 Responses to 溢出文本显示省略号,关于text-overflow:ellipsis的那些事

  1. bolo says:

    在一个列表里,有时候没必要把过长的文本进行隐藏。
    正常时可以固定 li 的高度并且 overflow: hidden ,mouse over 时则 height: auto;z-index: 99;overflow: visible;
    也就是当鼠标在元素上时则显示全部内容。

  2. 游神 says:

    收了,等会去试试我的那些个标题去

  3. 游神 says:

    我目前的做法:

  4. 游神 says:

    php echo mb_strimwidth(get_the_title(), 0, 34, ‘…’);

  5. 游神 says:

    复制PHP代码竟然无声无息就给我屏蔽了,邪恶的淫

  6. 任平生 says:

    原来 WebKit 也支持text-overflow 啊。

  7. Pingback: Tweets that mention 溢出文本显示省略号,关于text-overflow:ellipsis的那些事 - Leeiio Chaos Made. -- Topsy.com

  8. winy says:

    firefox居然不支持 ❓ 还是overflow: hidden吧

  9. Mars says:

    路过,学习啦。

  10. LOO2K says:

    leeiio,你博客上的 JavaScript 有点问题,外部链接点击之后会打开两个。
    $("a[rel*='external']").click(function() {
    window.open(this.href);
    return false;
    });

    应该是少了一句return false;

  11. 阿邙 says:

    之前也研究过这个问题 不过最后放弃了。

  12. Chris says:

    while() 那段还可以再优化, 现在这个例子根据截断的不同, 循环次数也不一样

  13. 行者 says:

    学的不是很好使,应该放个demo出来,有个参照。

  14. 小邪 says:

    呵呵,我一般喜欢让他们到下面去 ~
    word-break: break-all;
    word-wrap: break-word;
    😳 😳

  15. 行者 says:

    javascript 中调用的写法怎么写,恕我愚笨。 🙂

  16. disinfeqt says:

    曾经纠结了一整晚的问题终于到你头上了。
    你写的办法我当时都自己摸索出来了,除了那个恶心的XUL…
    最后还是PHP后台截断最省事…
    不过,最近一个项目里正巧用到了 text-overflow: ellipsis;
    真巧…

    • Leeiio says:

      @disinfeqt 呃,因为我们的doit后台不会处理这种问题的,都是前端问题的,所以当时纠结这个了好久,其实无非就是纠结在firefox下的问题,面对ellipsis问题它就是个异类。然后一直拖着没时间写博客分享…

  17. disinfeqt says:

    嗯那个JQ小插件留着备忘了,不错不错~ 😳

  18. QiQiBoY says:

    那个,火狐下我看到haha了。。 😮

  19. Chris says:

    今天处理等高问题, 发现离线 el 无法读取 offsetHeight, 想起你这里有用到 cloneNode 和 t.width(), 以为你有解决方案
    看了半天发现也是和我一样… visibility: hidden 后附加到 DOM 里… ❓

  20. comfill says:

    希望以后全人类都来用chrome吧。

  21. mm says:

    我用了那个xml文件,在火狐里居然显示是粗体字,其它正常,这是怎么回事呢?

  22. mm says:

    我的代码是这样的:
    #box #piaofu #piaofu-xia #piaofu-xia-xia #piaofu-xia-xiaduan li a {
    font-size: 12px;
    font-weight: normal;
    color: #FFF;
    display: block;
    overflow: hidden;
    white-space: nowrap;
    -o-text-overflow: ellipsis;
    text-overflow: ellipsis;
    -moz-binding: url(‘ellipsis.xml#ellipsis’);
    }
    字体的大小和粗细都定义了的,在IE和OPREA下显示正常,但是在FF下字体大小正常,但是就是显示粗体。

    • Leeiio says:

      @mm 先试试给font-weight: normal;加上!important变成font-weight: normal !important;,这个xml文件不会造成字体变粗的,有演示页面么

  23. mm says:

    :mrgreen: 问题已经解决,的确是我的CSS出现了问题,非常感谢!!!!

  24. mm says:

    是字体的继承问题,居然是继承最根部的字体定义。呵呵 :mrgreen:

  25. mm says:

    就是用了这个XML文件,FF的字体会自动继承最根部的定义,而IE和OPERA不字体的根部定义是什么,都必须在该子层中重新定义 :mrgreen:

  26. mm says:

    就是用了这个XML文件,FF的字体会自动继承最根部的定义,而IE和OPERA不管字体的根部定义是什么,都必须在该子层中重新定义

  27. mm says:

    再次感谢,感谢,再感谢 :mrgreen:

  28. 左旋肉碱 says:

    此文写的不错,学习了。。。

  29. 曾少 says:

    已拜读,已收藏,已RSS

  30. 鸡巴牛比 says:

    XML无法加载完成时,整行文字无法显示。该方法解决的那行文字,无法复制!不推荐使用。

  31. Ygs says:

    哟,学习了我

  32. 黑幕困兽 says:

    国内火狐用户感觉还是蛮少的,大部分都是开发人员在用,项目中我觉得不必要针对火狐来做这么多代码处理。
    不过方法很不错,赞! 😛

  33. Jill says:

    学习了 😳

  34. 这么多方法,学习了

  35. 宇蠢 says:

    逐个缩短字符宽度……汗死……
    这明显该用二分法的。

  36. Yuest says:

    另外,ff4.0上已经可以看到那个haha了
    还有,你的博客是不是有头像缓存啊,怎么我的头像没更新,我早在 gravatar 更新过了……

  37. 依云 says:

    火狐 7+ 支持 ellipssis 啦~

  38. Cherry says:

    我一般都设置好固定的width,超过部分就overflow:hidden了

  39. Jiuaisee says:

    9aisee: OOPS  学习!!

  40. Yaopeiling22 says:

    文本多行的时候,是不是只能用js来实现?

  41. Pingback: 显示12个字节 | 咖啡不苦

Leave a Reply

Your email address will not be published. Required fields are marked *