溢出文本顯示省略號,關於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, ‘…’);

  • 游神

    複製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個位元組 | 咖啡不苦()