跨浏览器多行文本溢出与省略号附加宽度和高度固定div?

我为这个问题做了一个形象,应该更容易理解。

文本溢出

我已经尝试了一些jQuery的插件,但找不到我正在寻找的。 有什么build议? 想法?

只是一个简单的基本想法。

我正在testing以下标记:

<div id="fos"> <p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Proin nisi ligula, dapibus a volutpat sit amet, mattis et dui. Nunc porttitor accumsan orci id luctus. Phasellus ipsum metus, tincidunt non rhoncus id, dictum a lectus. Nam sed ipsum a lacus sodales eleifend. Vestibulum lorem felis, rhoncus elementum vestibulum eget, dictum ut velit. Nullam venenatis, elit in suscipit imperdiet, orci purus posuere mauris, quis adipiscing ipsum urna ac quam.</p> </div> 

和CSS:

 #fos { width: 300px; height: 190px; overflow: hidden; } #fos p { padding: 10px; margin: 0; } 

应用这个jQuery将达到预期的效果:

 var $p = $('#fos p'); var divh = $('#fos').height(); while ($p.outerHeight() > divh) { $p.text(function (index, text) { return text.replace(/\W*\s(\S)*$/, '...'); }); } 

它反复尝试删除文本的最后一个单词,直到达到所需的大小。 由于溢出:隐藏; 这个过程依然是不可见的,即使JSclosures了,结果仍然是“视觉上正确的”(当然没有“…”)。

如果你把它和服务器端的一个明智的截断结合起来(只留下一小部分开销),那么它将运行得更快:)。

再次,这不是一个完整的解决scheme,只是一个想法。

更新:增加了一个jsFiddle演示 。

试试jQuery.dotdotdot插件。

 $(".ellipsis").dotdotdot(); 

用于“线夹”的Javascript库

请注意,“行夹紧”也称为“多行块省略”或“垂直省略”。


github.com/BeSite/jQuery.dotdotdot

  • 优点:麻省理工学院许可证,2.5Kb(缩小和gzipped),回购没有大的活动,但也不错
  • 缺点:jQuery依赖
  • 我的2美分: stackoverflow.com/questions/25187774/read-more-and-read-less-with-dotdotdot-jquery/29118739#29118739
  • 有帮助stackoverflow.com/questions/19015945/jquery-dotdotdot-expand-truncate-text-onclick
  • 有帮助gist.github.com/chiragparekh/c7e33dc749ed25544bde

github.com/josephschmitt/Clamp.js

  • 缺点:代码回购勉强活跃
  • 资讯性的reusablebits.com/post/2980974411/clamp-js-v0-2-explanations-and-performance

这里还有一些我还没有调查:

  • github.com/ftlabs/ftellipsis
  • github.com/micjamking/Succinct
  • github.com/pvdspek/jquery.autoellipsis和pvdspek.github.io/jquery.autoellipsis
  • github.com/rviscomi/trunk8
  • github.com/dobiatowski/jQuery.FastEllipsis
  • github.com/theproductguy/ThreeDots
  • github.com/tbasse/jquery-truncate
  • github.com/kbwood/more

线路夹紧的CSS解决scheme

有一些CSS解决scheme,但最简单的使用-webkit-line-clamp具有较差的浏览器支持 。 在jsfiddle.net/AdrienBe/jthu55v7/上查看现场演示

许多人为了仅使用CSS来做到这一点,付出了巨大的努力。 看到关于它的文章和问题:

  • css-tricks.com/line-clampin :坎普林线5星级文章
  • mobify.com/blog/multiline-ellipsis-in-pure-css :仅限CSS
  • cssmojo.com/line-clamp_for_non_webkit-based_browsers/:“mimic”-webkit-line-clamp在非webkit浏览器
  • 在CSS中,使用“…”表示溢出的多行块
  • 跨浏览器多行文本溢出与省略号附加宽度和高度固定div?
  • 如何只显示一个div(夹紧)的前几行?
  • 在一段中限制jquery的行数,并且最后应用三个时间段
  • 将文本长度限制为使用CSS的n行

我会推荐的

把事情简单化。 除非您有足够的时间专注于此function,否则请使用最简单的testing解决scheme:简单的CSS或经过良好testing的JavaScript库。

去做一些奇特/复杂/高度定制的东西,你会为此付出代价。


别人做什么

像Airbnb一样淡出可能是一个很好的解决scheme。 这可能是基本的CSS加上基本的jQuery。 实际上, CSSTricks上的这个解决scheme看起来非常相似

AirBnb“更多阅读”解决方案

哦,如果你寻找devise灵感:

  • smashingmagazine.com/2009/07/designing-read-more-and-continue-reading-links/ ,从2009年开始
  • Dribbble可能有有趣的devise…我找不到方法来收集他们虽然(通过search或标签),随意分享相关链接

HTML中没有这样的function,这是非常令人沮丧的。

我已经开发了一个库来处理这个问题。

  • 多行文本溢出:省略号
  • 使用不支持它的技术的多行文本:例如SVG,Canvas
  • 在SVG文本,HTML渲染和PDF导出中都有完全相同的换行符

看看我的网站的截图,教程和下载链接。

基于bažmegakapa的解决scheme的纯JS解决scheme,以及一些清理,以说明谁试图给高度/最大高度小于元素的lineHeight:

  var truncationEl = document.getElementById('truncation-test'); function calculateTruncation(el) { var text; while(el.clientHeight < el.scrollHeight) { text = el.innerHTML.trim(); if(text.split(' ').length <= 1) { break; } el.innerHTML = text.replace(/\W*\s(\S)*$/, '...'); } } calculateTruncation(truncationEl); 

我有一个很好的解决scheme,但使用渐变的省略号。 优点是你不必做任何JavaScript计算,它适用于可变宽度的容器,包括表格单元格。 它使用了一些额外的div,但它很容易实现。

http://salzerdesign.com/blog/?p=453

编辑:对不起,我不知道链接是不够的。 解决方法是在文本周围放置div,并设置div来控制溢出。 里面的div把另一个div与“渐变”渐变可以通过使用CSS或一个图像(对于旧的IE)。 渐变从表单元格的透明到背景颜色,比省略号宽一点。 如果文本很长并且溢出,则会进入“淡入淡出”区域并看起来“淡出”。 如果文字很短,淡入淡出是没有问题的。 通过将容器的高度设置为文本行高度的倍数,可以调整两个容器以显示一行或多行。 “淡入淡出”div可以被定位为只覆盖最后一行。

这是一个纯CSS的方式来完成这个: http : //www.mobify.com/blog/multiline-ellipsis-in-pure-css/

这里是一个总结:

在这里输入图像描述

 <html> <head> <style> html, body, p { margin: 0; padding: 0; font-family: sans-serif;} .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: -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); } </style> </head> <body> <div class="ellipsis"> <div> <p>Call me Ishmael.....</p> </div> </div> </body> </html> 

这个问题并不是一个确切的答案,但是当我尝试做类似的事情时遇到了这个页面,但是想添加一个链接到“查看更多”而不是简单的省略号。 这是一个jQuery函数,它将为溢出容器的文本添加一个“更多”链接。 就我个人而言,我使用Bootstrap,但它当然不会工作。

示例更多截图

要使用,请将文本放在容器中,如下所示:

 <div class="more-less"> <div class="more-block"> <p>The long text goes in here</p> </div> </div> 

当添加以下jQuery函数时,任何大于adjustheight值的div都将被截断并添加一个“More”链接。

 $(function(){ var adjustheight = 60; var moreText = '+ More'; var lessText = '- Less'; $(".more-less .more-block").each(function(){ if ($(this).height() > adjustheight){ $(this).css('height', adjustheight).css('overflow', 'hidden'); $(this).parent(".more-less").append ('<a style="cursor:pointer" class="adjust">' + moreText + '</a>'); } }); $(".adjust").click(function() { if ($(this).prev().css('overflow') == 'hidden') { $(this).prev().css('height', 'auto').css('overflow', 'visible'); $(this).text(lessText); } else { $(this).prev().css('height', adjustheight).css('overflow', 'hidden'); $(this).text(moreText); } }); }); 

基于此,但更新: http : //shakenandstirredweb.com/240/jquery-moreless-text

上面提到的dotdotdot jQuery插件可以很好地处理angular度:

 (function (angular) { angular.module('app') .directive('appEllipsis', [ "$log", "$timeout", function ($log, $timeout) { return { restrict: 'A', scope: false, link: function (scope, element, attrs) { // let the angular data binding run first $timeout(function() { element.dotdotdot({ watch: "window" }); }); } } } ]); })(window.angular); 

相应的标记是:

 <p app-ellipsis>{{ selectedItem.Description }}</p> 

下面是一个你可以在捏中使用的vanilla JavaScript解决scheme:

 // @param 1 = element containing text to truncate // @param 2 = the maximum number of lines to show function limitLines(el, nLines) { var nHeight, el2 = el.cloneNode(true); // Create clone to determine line height el2.style.position = 'absolute'; el2.style.top = '0'; el2.style.width = '10%'; el2.style.overflow = 'hidden'; el2.style.visibility = 'hidden'; el2.style.whiteSpace = 'nowrap'; el.parentNode.appendChild(el2); nHeight = (el2.clientHeight+2)*nLines; // Add 2 pixels of slack // Clean up el.parentNode.removeChild(el2); el2 = null; // Truncate until desired nLines reached if (el.clientHeight > nHeight) { var i = 0, imax = nLines * 35; while (el.clientHeight > nHeight) { el.innerHTML = el.textContent.slice(0, -2) + '&hellip;'; ++i; // Prevent infinite loop in "print" media query caused by // Bootstrap 3 CSS: a[href]:after { content:" (" attr(href) ")"; } if (i===imax) break; } } } limitLines(document.getElementById('target'), 7); 
 #test { width: 320px; font-size: 18px; } 
 <div id="test"> <p>Paragraph 1</p> <p id="target">Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.</p> <p>Paragraph 3</p> </div> 

编辑:来到整个剃须这是JS插件,基于给定的最大高度确实很好地做多行文本截断。 它使用二进制search来find最佳的中断点。 绝对值得调查。


原文答案:

我不得不为这个问题想出一个香草JS解决scheme。 在我工作的情况下,我必须把一个长的产品名称放在有限的宽度和两行以上; 如果需要,由省略号截断。

我使用各种SOpost的答案来制作符合我需要的东西。 策略如下:

  1. 计算所需字体大小的字体变体的平均字符宽度。
  2. 计算容器的宽度
  3. 计算适合容器中一行的字符数
  4. 根据适合一行的字符数和文本应该换行的行数,计算截断string的字符数。
  5. 根据以前的计算截断input文本(考虑省略号添加的额外字符)并将“…”附加到结尾

代码示例:

 /** * Helper to get the average width of a character in px * NOTE: Ensure this is used only AFTER font files are loaded (after page load) * @param {DOM element} parentElement * @param {string} fontSize */ function getAverageCharacterWidth(parentElement, fontSize) { var textSample = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890!@#$%^&*()"; parentElement = parentElement || document.body; fontSize = fontSize || "1rem"; var div = document.createElement('div'); div.style.width = "auto"; div.style.height = "auto"; div.style.fontSize = fontSize; div.style.whiteSpace = "nowrap"; div.style.position = "absolute"; div.innerHTML = textSample; parentElement.appendChild(div); var pixels = Math.ceil((div.clientWidth + 1) / textSample.length); parentElement.removeChild(div); return pixels; } /** * Helper to truncate text to fit into a given width over a specified number of lines * @param {string} text Text to truncate * @param {string} oneChar Average width of one character in px * @param {number} pxWidth Width of the container (adjusted for padding) * @param {number} lineCount Number of lines to span over * @param {number} pad Adjust this to ensure optimum fit in containers. Use a negative value to Increase length of truncation, positive values to decrease it. */ function truncateTextForDisplay(text, oneChar, pxWidth, lineCount, pad) { var ellipsisPadding = isNaN(pad) ? 0 : pad; var charsPerLine = Math.floor(pxWidth / oneChar); var allowedCount = (charsPerLine * (lineCount)) - ellipsisPadding; return text.substr(0, allowedCount) + "..."; } //SAMPLE USAGE: var rawContainer = document.getElementById("raw"); var clipContainer1 = document.getElementById("clip-container-1"); var clipContainer2 = document.getElementById("clip-container-2"); //Get the text to be truncated var text=rawContainer.innerHTML; //Find the average width of a character //Note: Ideally, call getAverageCharacterWidth only once and reuse the value for the same font and font size as this is an expensive DOM operation var oneChar = getAverageCharacterWidth(); //Get the container width var pxWidth = clipContainer1.clientWidth; //Number of lines to span over var lineCount = 2; //Truncate without padding clipContainer1.innerHTML = truncateTextForDisplay(text, oneChar, pxWidth, lineCount); //Truncate with negative padding value to adjust for particular font and font size clipContainer2.innerHTML = truncateTextForDisplay(text, oneChar, pxWidth, lineCount,-10); 
 .container{ display: inline-block; width: 200px; overflow: hidden; height: auto; border: 1px dotted black; padding: 10px; } 
 <h4>Untruncated</h4> <div id="raw" class="container"> This is super long text which needs to be clipped to the correct length with ellipsis spanning over two lines </div> <h4>Truncated</h4> <div id="clip-container-1" class="container"> </div> <h4>Truncated with Padding Tweak</h4> <div id="clip-container-2" class="container"> </div> 

如果没有像Courier这样的固定宽度的字体,你可能无法做到(目前?)。 对于固定宽度的字体,每个字母都占据相同的水平空间,因此您可以计算字母数,并将结果与​​当前字体大小(ems或exs)相乘。 那么你只需要testing一行中有多less个字母,然后再分解。

或者,对于非固定字体,您可以创build所有可能字符(如i = 2px,m = 5px)的映射,然后进行math运算。 虽然很多丑陋的工作。

要扩展@ DanMan的解决scheme:在使用可变宽度字体的情况下,可以使用平均字体宽度。 这有两个问题:1)太多W的文本会溢出; 2)太多的文本会被截断。

或者你可以采取最坏的方法,并使用字母“W”(我相信是最宽的)的宽度。 这消除了上面的问题1,但是加剧了问题2。

一个不同的方法可能是:离开overflow: clip在div中,并添加一个省略号部分(也许另一个div或图像)与float: right; position: relative; bottom: 0px; float: right; position: relative; bottom: 0px; (未经testing)。 诀窍是使图像出现在文本的结尾之上。

你也可以只显示图像,当你知道它会溢出(比如约100个字符后)

有了这个代码,如果元素的高度受限于最大高度风格,则不需要额外的包装div。

 // Shorten texts in overflowed paragraphs to emulate Operas text-overflow: -o-ellipsis-lastline $('.ellipsis-lastline').each(function(i, e) { var $e = $(e), original_content = $e.text(); while (e.scrollHeight > e.clientHeight) $e.text($e.text().replace(/\W*\w+\W*$/, '…')); $e.attr('data-original-content', original_content); }); 

另外它将原始文本保存在只能使用样式显示的数据属性中,例如。 在鼠标hover在:

 .ellipsis-lastline { max-height: 5em; } .ellipsis-lastline:before { content: attr(data-original-content); position: absolute; display: none; } .ellipsis-lastline:hover:before { display: block; } 

纯JS演示(没有jQuery和'while'循环)

当我search多行省略号问题的解决scheme时,我感到惊讶的是没有没有jQuery没有好的一个。 还有一些基于'while'循环的解决scheme,但是由于可能进入无限循环,我认为它们不是有效的和危险的。 所以我写了这个代码:

 function ellipsizeTextBox(el) { if (el.scrollHeight <= el.offsetHeight) { return; } let wordArray = el.innerHTML.split(' '); const wordsLength = wordArray.length; let activeWord; let activePhrase; let isEllipsed = false; for (let i = 0; i < wordsLength; i++) { if (el.scrollHeight > el.offsetHeight) { activeWord = wordArray.pop(); el.innerHTML = activePhrase = wordArray.join(' '); } else { break; } } let charsArray = activeWord.split(''); const charsLength = charsArray.length; for (let i = 0; i < charsLength; i++) { if (el.scrollHeight > el.offsetHeight) { charsArray.pop(); el.innerHTML = activePhrase + ' ' + charsArray.join('') + '...'; isEllipsed = true; } else { break; } } if (!isEllipsed) { activePhrase = el.innerHTML; let phraseArr = activePhrase.split(''); phraseArr = phraseArr.slice(0, phraseArr.length - 3) el.innerHTML = phraseArr.join('') + '...'; } } let el = document.getElementById('ellipsed'); ellipsizeTextBox(el); 

非常简单的function会做。

指示:

  $scope.truncateAlbumName = function (name) { if (name.length > 36) { return name.slice(0, 34) + ".."; } else { return name; } }; 

视图:

 <#p>{{truncateAlbumName(album.name)}}<#/p> 

不知道这是你在找什么,它使用最小高度而不是高度。

  <div id="content" style="min-height:10px;width:190px;background:lightblue;"> <?php function truncate($text,$numb) { // source: www.kigoobe.com, please keep this if you are using the function $text = html_entity_decode($text, ENT_QUOTES); if (strlen($text) > $numb) { $text = substr($text, 0, $numb); $etc = "..."; $text = $text.$etc; } $text = htmlentities($text, ENT_QUOTES); return $text; } echo truncate("this is a multi-lines text block, some lines inside the div, while some outside", 63); ?> </div>