溢出文本显示省略号,关于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!

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

    • @bolo 纵向的其实也可以用文中的js来实现,至于你说的过长的文本,万一很长,你鼠标mouseover的时候显现也是挺奇怪的吧

    • @Leeiio 如果是列出标题的话,一般都不会有过长的现象。
      PS:大雄加我GT吧,到后台看我邮件地址。

    • @bolo
      mouseover 的使用 popup 会比较好吧, 比起强硬更改大小要好

    • @Chris 我说的有点不准确,应该是hover的时候,完全用css实现

    • @bolo 加了,你那边没反映咩

  • 游神

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

  • 游神

    我目前的做法:

  • 游神

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

    • @游神 🙄 感觉像这样在源头控制比较好~~~

    • 游神

      @MOPVHS
      是的 我会抓紧折腾折腾

  • 游神

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

  • 原来 WebKit 也支持text-overflow 啊。

    • @任平生 是啊,不过text-overflow目前在w3c文档里已经被抹掉了,不知道为何。

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

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

    • @winy overflow hidden只剩下半截字还是挺奇怪的。

  • 路过,学习啦。

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

    应该是少了一句return false;

    • @LOO2K 感谢提醒,不过不是你说的问题,是事件重复绑定的问题,造成了两次事件所以弹出了两个窗口。

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

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

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

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

    • @小邪 如果是我截图中的左侧这种,就没法让他换行显示了。

    • @Leeiio _( ̄0 ̄)_[哦~],也是哈,嘿嘿,木有发现 ~

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

    • @行者 调用什么?

    • @Leeiio

      $(document).ready(function(){
      $(“p”).ellipsis(200);
      });

      这样调用不行,应该怎么写?

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

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

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

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

    • @QiQiBoY 不可能,你看的是上面的哈哈,下面的哈哈我发现页面在firefox下有问题,一整段的演示效果都没显示出来。。

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

  • comfill

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

  • mm

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

  • mm

    我的代码是这样的:
    #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下字体大小正常,但是就是显示粗体。

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

  • mm

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

  • mm

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

  • mm

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

  • mm

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

  • mm

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

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

  • 已拜读,已收藏,已RSS

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

  • Ygs

    哟,学习了我

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

  • Jill

    学习了 😳

  • 这么多方法,学习了

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

  • 更高效率的 jQuery 插件
    http://yue.st/notes/code/js/ellipsis.zh.html

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

  • 火狐 7+ 支持 ellipssis 啦~

  • Cherry

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

    • John Xiao

      如何加 … 字符?

  • Jiuaisee

    9aisee: OOPS  学习!!

  • Yaopeiling22

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

    • IT男

      同问啊~多好的各位有什么好办法么?

    • Unopoo

      这里有个纯css的多行文本的解决方法, 我没看太懂, 不过你们可以看一下, 然后教教我它什么原理:

      http://jsfiddle.net/barney/bmNvs/

    • Guest

      这里有个纯css的多行文本解决方法, 你可以看一下:
      http://jsfiddle.net/barney/bmNvs/

  • Pingback: 显示12个字节 | 咖啡不苦()