跨浏览器的多行文本溢出,省略了宽度和高度附加的省略号“

我为这个问题制作了一个图像,以便更容易理解。

是否可以在具有固定宽度和多行的

上创建省略号?

文本溢出

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

只是一个快速的基本想法。

我正在使用以下标记进行测试:

 

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.

和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)*$/, '...'); }); } 

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

如果你将它与服务器端的合理截断相结合(只留下很小的开销),那么它将运行得更快:)。

同样,这不是一个完整的解决方案,只是一个想法。

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

试试jQuery.dotdotdot插件。

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

用于“线夹”的Javascript库

注意,“线夹”也称为“多线块上的省略号”或“垂直省略号”。


github.com/BeSite/jQuery.dotdotdot

  • 优点:麻省理工学院许可证,2.5Kb(缩小和压缩),在回购时没有大的活动但也不错
  • 缺点: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解决方案

有一些CSS解决方案,但最简单的用途是-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/ :非模仿webkit浏览器中的“模仿”-webkit-line-clamp
  • 使用CSS,使用“…”表示溢出的多行块
  • 跨浏览器多行文本溢出与省略号附加在宽度和高度固定div?
  • 如何仅显示div的前几行(钳位)?
  • jquery限制段落中的行并将三个句点应用到结尾
  • 使用CSS将文本长度限制为n行

我推荐的是什么

把事情简单化。 除非您有足够的时间专注于此function,否则请选择最简单且经过测试的解决方案:简单的CSS或经过良好测试的JavaScript库。

寻找花哨/复杂/高度定制的东西,你将为此付出代价。


别人怎么做

像Airbnb一样淡出可能是一个很好的解决方案。 它可能是基本的CSS加上基本的jQuery。 实际上,它似乎与CSSTricks上的这个解决方案非常相似

AirBnb“阅读更多”解决方案

哦,如果你寻找设计灵感:

  • smashingmagazine.com/2009/07/designing-read-more-and-continue-reading-links/ ,从2009年开始……
  • Dribbble可能有一些有趣的设计……我找不到收集它们的方法(通过搜索或标签),随意分享相关链接

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

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

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

查看我的网站以获取屏幕截图,教程和下载链接。

纯粹的JS解决方案基于bažmegakapa的解决方案,并进行一些清理以解释那些试图给出高度/最大高度小于元素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); 

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

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

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

以下是实现此目的的纯CSS方法: http : //www.mobify.com/blog/multiline-ellipsis-in-pure-css/

以下是摘要:

在此处输入图像描述

      

Call me Ishmael.....

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

示例更多截图

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

 

The long text goes in here

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

 $(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 ('' + moreText + ''); } }); $(".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); 

相应的标记将是:

 

{{ selectedItem.Description }}

这是一个可以在紧要关头使用的vanilla JavaScript解决方案:

 // @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) + '…'; ++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; } 
 

Paragraph 1

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.

Paragraph 3

编辑:穿过Shave这是一个JS插件,可以很好地根据给定的最大高度进行多行文本截断。 它使用二分搜索来找到最佳断点。 绝对值得研究。


原始答案:

我不得不为这个问题想出一个vanilla JS解决方案。 在我工作的情况下,我必须将长的产品名称放入有限的宽度和超过两行; 如果需要,用省略号截断。

我使用各种SOpost的答案来烹饪符合我需求的东西。 策略如下:

  1. 计算所需字体大小的字体变体的平均字符宽度。
  2. 计算容器的宽度
  3. 计算适合容器中一行的字符数
  4. 根据一行中适合的字符数和文本应该包裹的行数,计算要截断字符串的字符数。
  5. 根据先前的计算截断输入文本(考虑省略号添加的额外字符)并将“…”追加到末尾

代码示例:

 /** * 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; } 
 

Untruncated

This is super long text which needs to be clipped to the correct length with ellipsis spanning over two lines

Truncated

Truncated with Padding Tweak

也许很晚但使用SCSS你可以声明一个函数,如:

 @mixin clamp-text($lines, $line-height) { overflow: hidden; text-overflow: ellipsis; display: -webkit-box; -webkit-box-orient: vertical; -webkit-line-clamp: $lines; line-height: $line-height; max-height: unquote('#{$line-height*$lines}em'); @-moz-document url-prefix() { position: relative; height: unquote('#{$line-height*$lines}em'); &::after { content: ''; text-align: right; position: absolute; bottom: 0; right: 0; width: 30%; height: unquote('#{$line-height}em'); background: linear-gradient( to right, rgba(255, 255, 255, 0), rgba(255, 255, 255, 1) 50% ); } } } 

并使用它像:

 .foo { @include clamp-text(1, 1.4); } 

这会将文本截断为一行,并知道它的行高为1.4。 预期的输出是chrome,最后用...渲染,最后用FF渲染

火狐

在此处输入图像描述

在此处输入图像描述

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

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

扩展@DanMan的解决方案:在使用可变宽度字体的情况下,您可以使用平均字体宽度。 这有两个问题:1)具有太多W的文本将溢出; 2)具有太多I的文本将被更早地截断。

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

一种不同的方法可能是:保留overflow: clip在div中overflow: clip并使用float: right; position: relative; bottom: 0px;添加省略号部分(可能是另一个div或图像) float: right; position: relative; bottom: 0px; float: right; position: relative; bottom: 0px; (未经测试)。 诀窍是使图像出现在文本的末尾。

您也可以只在知道图像溢出时显示图像(例如,大约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’循环)

当我搜索多行省略号问题的解决方案时,我很惊讶没有jQuery没有任何好的。 还有一些基于’while’循环的解决方案,但我认为由于可能进入无限循环,它们不是有效且危险的。 所以我写了这段代码:

 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,我还需要告诉函数无论字体大小或容器大小如何都要显示多少行。

我的解决方案基于使用Canvas.measureText方法(这是一个HTML5function),如Domi所述 ,因此它不是完全跨浏览器的。

你可以看到它如何在这个小提琴上运作。

这是代码:

 var processTexts = function processTexts($dom) { var canvas = processTexts .canvas || (processTexts .canvas = document.createElement("canvas")); $dom.find('.block-with-ellipsis').each(function (idx, ctrl) { var currentLineAdded = false; var $this = $(ctrl); var font = $this.css('font-family').split(",")[0]; //This worked for me so far, but it is not always so easy. var fontWeight = $(this).css('font-weight'); var fontSize = $(this).css('font-size'); var fullFont = fontWeight + " " + fontSize + " " + font; // re-use canvas object for better performance var context = canvas.getContext("2d"); context.font = fullFont; var widthOfContainer = $this.width(); var text = $.trim(ctrl.innerHTML); var words = text.split(" "); var lines = []; //Number of lines to span over, this could be calculated/obtained some other way. var lineCount = $this.data('line-count'); var currentLine = words[0]; var processing = ""; var isProcessing = true; var metrics = context.measureText(text); var processingWidth = metrics.width; if (processingWidth > widthOfContainer) { for (var i = 1; i < words.length && isProcessing; i++) { currentLineAdded = false; processing = currentLine + " " + words[i]; metrics = context.measureText(processing); processingWidth = metrics.width; if (processingWidth <= widthOfContainer) { currentLine = processing; } else { if (lines.length < lineCount - 1) { lines.push(currentLine); currentLine = words[i]; currentLineAdded = true; } else { processing = currentLine + "..."; metrics = context.measureText(processing); processingWidth = metrics.width; if (processingWidth <= widthOfContainer) { currentLine = processing; } else { currentLine = currentLine.slice(0, -3) + "..."; } lines.push(currentLine); isProcessing = false; currentLineAdded = true; } } } if (!currentLineAdded) lines.push(currentLine); ctrl.innerHTML = lines.join(" "); } }); }; (function () { $(document).ready(function () { processTexts($(document)); }); })(); 

使用它的HTML将是这样的:

 
VERY LONG TEXT THAT I WANT TO BREAK IN LINES. VERY LONG TEXT THAT I WANT TO BREAK IN LINES.

获取font-family的代码相当简单,在我的情况下可以工作,但对于更复杂的场景,您可能需要使用这些内容 。

另外,在我的情况下,我告诉函数要使用多少行,但您可以根据容器大小和字体计算要显示的行数。

在这里,我用更快的算法创建了另一个库 请检查:

https://github.com/i-ahmed-biz/fast-ellipsis

使用凉亭安装:

 bower install fast-ellipsis 

要使用npm安装:

 bower install fast-ellipsis 

希望你喜欢!

非常简单的JavaScript解决方案。 Div必须用fe表示:

 .croppedTexts { max-height: 32px; overflow: hidden; } 

和JS:

 var list = document.body.getElementsByClassName("croppedTexts"); for (var i = 0; i < list.length; i++) { cropTextToFit(list[i]); } function cropTextToFit (o) { var lastIndex; var txt = o.innerHTML; if (!o.title) o.title = txt; while (o.scrollHeight > o.clientHeight) { lastIndex = txt.lastIndexOf(" "); if (lastIndex == -1) return; txt = txt.substring(0, lastIndex); o.innerHTML = txt + "…"; } } 

我做了一个让html完好无损的版本。 jsfiddle的例子

jQuery的

 function shorten_text_to_parent_size(text_elem) { textContainerHeight = text_elem.parent().height(); while (text_elem.outerHeight(true) > textContainerHeight) { text_elem.html(function (index, text) { return text.replace(/(?!(<[^>]*>))\W*\s(\S)*$/, '...'); }); } } $('.ellipsis_multiline').each(function () { shorten_text_to_parent_size($(this)) }); 

CSS

 .ellipsis_multiline_box { position: relative; overflow-y: hidden; text-overflow: ellipsis; } 

jsfiddle的例子

不确定这是否是您正在寻找的,它使用最小高度而不是高度。

  
$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); ?>

非常简单的func会做。

指示:

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

视图:

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