本文翻译自CSS Ellipsis: How to Manage Multi-Line Ellipsis in Pure CSS,文中某些部分有些许改动,并添加译者的一些感想,请各位读者谅解。javascript
合理的截断多行文本是件不容易的事情,咱们一般采用几种方法解决:css
overflow: hidden
直接隐藏多余的文本html
text-overflow: ellipsis
只适用于单行文本的处理java
各类比较脆弱的javascript实现。之因此说这种实现比较脆弱是因为须要文本长度的变化时刻获得回流(relayout)后的布局信息,如宽度web
原文写做时间是2012.9.18号,比较有意义的一天。不过做者忽略了WebKit提供的一个扩展属性
-webkit-line-clamp
,它并非CSS规范中的属性。利用该属性实现多行文本的省略号显示须要配合其余三个属性:display: -webkit-box
、-webkit-box-orient
、text-overflow: ellipsis;
。其中,-webkit-line-clamp
设置块元素包含的文本行数;display: -webkit-box
设置块元素的布局为伸缩布局;-webkit-box-orient
设置伸缩项的布局方向;text-overflow: ellipsis;
则表示超出盒子的部分使用省略号表示。浏览器
不过本文将要介绍的方法是采用CSS规范中的属性,并结合特殊的实现技巧完成的。这意味着在实现CSS2.1规范的浏览器中都是能够兼容的,不将仅仅是纯粹的移动端领域,在传统的PC浏览器(大家懂得我指的是哪些浏览器)中还是可行的。好吧,让咱们一块儿见识下。布局
咱们把实现的细节划分为7个步骤,在这个实现过程当中最简单的就是截断文本,而最难的部分则是让一个元素处在其父包含块溢出时的右下方,而且当父元素未溢出时该元素消失不可见。为了去难避易,咱们先从比较简单的地方开始--当父包含框比较小时,将子元素布局到父包含框的右下角。优化
其实这个实现彻底利用了元素浮动的基本规则。在这里不详细讲解CSS2.1规范中的几种情形,不明白的读者自行查阅。这段代码实现很简单,就是三个子元素和包含块的高度及浮动设置:url
<div class="wrap"> <div class="prop">1.prop<br>float:left</div> <div class="main">2.main<br>float:right<br>Fairly short text</div> <div class="end">3.end<br>float:right</div> </div> .wrap { width: 400px; height: 200px; margin: 20px 20px 50px; border: 5px solid #AAA; line-height: 25px; } .prop { float: left; width: 100px; height: 200px; background: #FAF; } .main { float: right; width: 300px; background: #AFF; } .end { float: right; width: 100px; background: #FFA; }
咱们经过建立一个子元素来替代将要显示的省略号,当文本溢出的情形下该元素显示在正确的位置上。在接下来的实现中,咱们建立了一个realend元素,并利用上一节end元素浮动后的位置来实现realend元素的定位。spa
<div class="wrap"> <div class="prop"> 1.prop<br> float:right</div> <div class="main"> 2.main<br> float:left<br> Fairly short text</div> <div class="end"> <div class="realend"> 4.realend<br> position:absolute</div> 3.end<br>float:right </div> </div> .end { float: right; position: relative; width: 100px; background: #FFA; } .realend { position: absolute; width: 100%; top: -50px; left: 300px; background: #FAA; font-size: 13px; }
这一步中,咱们主要关心的是realend元素的定位,基于浮动后的end元素设置偏移量,当end元素浮动到第一节第二章图的位置时(即在prop元素的下方),此时realend元素正好处在end元素的上方50px,右侧300px-100px=200px处,而该位置正是父包含框wrap元素的右下角,此时正是咱们期待的结果:
若父元素并无溢出,那么realend元素会出如今其右侧
这种状况解决很简单,请看下文之第七节,此处仅做实例说明。
在第二节中,咱们针对end元素设置了相对定位,对realend元素设置绝对定位。可是咱们能够采用更为简单的代码来实现,即只使用相对定位。熟悉定位模型的同窗应该知道,相对定位的元素仍然占据文本流,同时仍可针对元素设置偏移。这样,就能够去掉end元素,仅针对realend元素设置相对定位。
<div class="wrap"> <div class="prop">1.prop<br>float:right</div> <div class="main">2.main<br>float:left<br>Fairly short text</div> <div class="realend"> 3.realend<br>position:relative</div> </div> .realend { float: right; position: relative; width: 100px; top: -50px; left: 300px; background: #FAA; font-size: 14px; }
其余的属性并不改变,效果同样。
目前,最左侧的prop元素的做用在于让realend元素在文本溢出时处在其正下方,在前几节的示例代码中为了直观的演示,设置prop元素的宽度为100px,那么如今为了更好的模拟实际的效果,咱们缩小逐渐缩小prop元素的宽度。
<div class="wrap"> <div class="prop">1.prop<br>float:right</div> <div class="main">2.main<br>float:left<br>Fairly short text</div> <div class="realend"> 3.realend<br>position:relative</div> </div> .prop { float: left; width: 5px; height: 200px; background: #F0F; } .main { float: right; width: 300px; margin-left: -5px; background: #AFF; } .realend { float: right; position: relative; top: -50px; left: 300px; width: 100px; margin-left: -100px; padding-right: 5px; background: #FAA; font-size: 14px; }
针对prop元素,缩小宽度为5px,其他属性不变;
针对main元素,设置margin-left:5px,让main元素左移5px,这样main元素在宽度上就彻底占满了父元素;
对于realend元素,top、left和width的值不变。而设置margin-left: -100px
、padding-right: 5px
则是为了让realend元素的盒模型的最终宽度计算为5px。
BoxWidth = ChildMarginLeft + ChildBorderLeftWidth + ChildPaddingLeft + ChildWidth + ChildPaddingLeft + ChildBorderRightWidth + ChildMarginRightWidth;
具体可参考我以前的文章负margin的原理以及应用一文。
因为CSS规范规定padding的值不能够为负数,所以只有设置margind-left为负值,且等于其宽度。这样作的最终目的就是保证realend元素处在prop元素的下方,保证在文本溢出的状况下定位准确性:
目前,realend元素的相关属性仍采用px度量,为了更好的扩展性,能够改用%替代。
同时,prop元素和realend元素能够采用伪元素来实现,减小额外标签的使用。
<div class="ellipsis"> <div>2.main<br>float:left<br>Fairly short text </div> </div> /*至关于以前的prop元素*/ .ellipsis:before { content: ""; float: left; width: 5px; height: 200px; background: #F0F; } /*至关于以前的main元素*/ .ellipsis > *:first-child { float: right; width: 100%; margin-left: -5px; background: #AFF; } /*至关于以前的realend元素*/ .ellipsis:after { content: "realend"; float: right; position: relative; top: -25px; left: 100%; width: 100px; margin-left: -100px; padding-right: 5px; background: #FAA; font-size: 14px; }
效果图和上节同样。
以前的实现中在文本未溢出的状况下,realend元素会出如今父元素的右侧,正如。解决此问题很简单,急须要设置:
.ellipsis{ overflow:hidden; }
便可解决问题。
如今咱们离结完就差一步了,即去掉各元素的背景色,而且用“...”替换文本。最后为了优化体验,采用渐变来隐藏“...”覆盖的文本,并设置了一些兼容性的属性。
到了此处,相信如今关心的只是CSS的代码了:
.ellipsis { overflow: hidden; height: 200px; line-height: 25px; margin: 20px; border: 5px solid #AAA; } .ellipsis:before { content:""; float: left; width: 5px; height: 200px; } .ellipsis > *:first-child { float: right; width: 100%; margin-left: -5px; } .ellipsis:after { content: "\02026"; box-sizing: content-box; -webkit-box-sizing: content-box; -moz-box-sizing: content-box; float: right; position: relative; top: -25px; left: 100%; width: 3em; margin-left: -3em; padding-right: 5px; text-align: right; background-size: 100% 100%; /* 512x1 image, gradient for IE9. Transparent at 0% -> white at 50% -> white at 100%.*/ background-image: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAgAAAAABCAMAAACfZeZEAAAABGdBTUEAALGPC/xhBQAAAwBQTFRF////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////AAAA////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////wDWRdwAAAP90Uk5TgsRjMZXhS30YrvDUP3Emow1YibnM9+ggOZxrBtpRRo94gxItwLOoX/vsHdA2yGgL8+TdKUK8VFufmHSGgAQWJNc9tk+rb5KMCA8aM0iwpWV6dwP9+fXuFerm3yMs0jDOysY8wr5FTldeoWKabgEJ8RATG+IeIdsn2NUqLjQ3OgBDumC3SbRMsVKsValZplydZpZpbJOQco2KdYeEe36BDAL8/vgHBfr2CvTyDu8R7esU6RcZ5ecc4+Af3iLcJSjZ1ivT0S/PMs3LNck4x8U7wz7Bv0G9RLtHuEq1TbJQr1OtVqqnWqRdoqBhnmSbZ5mXapRtcJGOc4t2eYiFfH9AS7qYlgAAARlJREFUKM9jqK9fEGS7VNrDI2+F/nyB1Z4Fa5UKN4TbbeLY7FW0Tatkp3jp7mj7vXzl+4yrDsYoVx+JYz7mXXNSp/a0RN25JMcLPP8umzRcTZW77tNyk63tdprzXdmO+2ZdD9MFe56Y9z3LUG96mcX02n/CW71JH6Qmf8px/cw77ZvVzB+BCj8D5vxhn/vXZh6D4uzf1rN+Cc347j79q/zUL25TPrJMfG/5LvuNZP8rixeZz/mf+vU+Vut+5NL5gPOeb/sd1dZbTs03hBuvmV5JuaRyMfk849nEM7qnEk6IHI8/qn049hB35QGHiv0yZXuMdkXtYC3ebrglcqvYxoj1muvC1nDlrzJYGbpcdHHIMo2FwYv+j3QAAOBSfkZYITwUAAAAAElFTkSuQmCC); background: -webkit-gradient(linear, left top, right top, from(rgba(255, 255, 255, 0)), to(white), color-stop(50%, white)); background: -moz-linear-gradient(to right, rgba(255, 255, 255, 0), white 50%, white); background: -o-linear-gradient(to right, rgba(255, 255, 255, 0), white 50%, white); background: -ms-linear-gradient(to right, rgba(255, 255, 255, 0), white 50%, white); background: linear-gradient(to right, rgba(255, 255, 255, 0), white 50%, white); }
从上文的实现细节来看,咱们利用的技巧彻底是CSS规范中的浮动+定位+盒模型宽度计算,惟一存在兼容性问题的在于无关痛痒的渐变实现,所以能够在大多数浏览器下进行尝试。