跨浏览器的多行文本溢出,并在固定的宽度和高度内附加了省略号


177

我为这个问题制作了一个图像,以使其更易于理解。

是否可以在<div>具有固定宽度和多行的上创建省略号?

文字溢出

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



1
stackoverflow.com/questions/3922739/…仅适用于css的解决方案
Evgeny 2013年


2
对于任何在2016年中期寻找此内容的人来说,简短的答案是:不,这不可能以优雅的跨浏览器和CSS唯一方式实现。通常最接近完整的解决方案(codepen.io/romanrudenko/pen/ymHFh)是如此戈德伯格式的,它使您的整个身体受伤,而且仍然很丑陋。
康拉德'16

Answers:


91

只是一个基本的想法。

我正在测试以下标记:

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

它反复尝试删除文本的最后一个单词,直到达到所需的大小。由于溢出:隐藏;该过程仍然不可见,即使关闭了JS,结果仍保持“视觉上正确”(当然不带“ ...”)。

如果将其与服务器端的合理截断功能结合在一起(仅会产生少量开销),那么它将运行得更快:)。

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

更新:添加了jsFiddle演示


1
很棒的解决方案@bazmegakapa ...但我在尝试使其适应我的情况时遇到了一些问题。我有各种各样的li东西,每个里面都有一个.block和一个.block h2,我需要将此应用到h2里面,.block但是我无法使它正常工作。如果多于一个,有什么不同.block h2吗?
亚历克斯(Alex)

1
在我的情况下,本应只剩 3行,而只剩 2行文本。显然,我的容器比一行小height*3了几个像素。 简单的解决方法是简单的几个像素增加divh
卢卡斯LT

3
我对此脚本有无限循环的糟糕经验,因为文本仅包含一个很长的单词,因此替换regexp从未匹配。为避免这种情况,请在以下while行之后添加此代码:if(!$p.text().match(/\W*\s(\S)*$/)) break;
KrisWebDev 2014年

1
虽然在这种情况下不太可能成为问题,但更新DOM并反复检查布局不是一个好主意,因为这可能会导致速度变慢。为了减轻这种情况,您可以执行类似于二分查找的操作:测试以查看文本块是否已适合,否则将文本拆分为单词或字符并定义边界(低位= 1个单词/字符,高位=所有单词/字符) ,while ((upper-lower)>1) {let middle=((lower+upper)/2)|0 /*|0 is quick floor*/; if (test(words.slice(0,middle)+'...')) {lower=middle;} else {upper=middle;}}。正如@KrisWebDev发现的那样,您还需要检查一个大字。
Chinoto Vokro

1
这个解决方案很棒。就我而言,我需要跟踪原始文本,以便可以响应地截断全文本值。因此,在页面加载时,我将原始文本存储在一个变量中,在运行此逻辑之前,请确保使用原始文本值“刷新”该元素。添加去抖动,效果非常好。
besseddrest

68

尝试使用jQuery.dotdotdot插件。

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

11
你会怎么发音?点-点-点-点?
JackAce 2012年

58
真的很费劲地使用> 600行js解决了CSS应该解决的问题
Jethro Larson 2013年

我已经尝试过了,它工作正常。应该是公认的答案
AbdelHady 2013年

1
可以,但是请确保使用window.loaded事件而不是$(document).ready(),因为字体和其他外部资源可能会影响HTML的布局。如果dotdotdot在加载这些资源之前执行,则文本不会在正确的位置被截断。
sboisse,2015年

10
这是一种商业工具,单个站点收费5美元,多个站点收费35美元。许可会很痛苦。我认为它是免费的并且可以立即集成,但事实并非如此!
基因b。

29

用于“线夹”的JavaScript库

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


github.com/BeSite/jQuery.dotdotdot


github.com/josephschmitt/Clamp.js


这里还有一些我尚未调查的内容:


CSS线夹解决方案

有一些CSS解决方案,但最简单的用法-webkit-line-clamp却缺乏对浏览器的支持。观看jsfiddle.net/AdrienBe/jthu55v7/上的实时演示

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


我会推荐什么

把事情简单化。除非您有大量时间专用于此功能,否则请选择最简单且经过测试的解决方案:简单的CSS或经过良好测试的javascript库。

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


别人做什么

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

AirBnb“了解更多”解决方案

哦,如果您正在寻找设计灵感:


6

HTML中没有此类功能,这非常令人沮丧。

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

  • 多行文字溢出:省略号
  • 具有不支持该功能的多行文字:例如SVG,例如Canvas
  • 例如,SVG文本,HTML渲染和PDF导出中的换行符完全相同

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


“建立数据库连接时出错” ...您可能想像其他人一样在Github上托管您的项目,这可能对您和对社区都更好:)
Adrien

@Adrien是在Github上:github.com/rossille/jstext,您是对的,github比我的网站更稳定,我将github页面设置为主链接
Samuel Rossille 2014年

@SamuelRossille好消息,感谢您的快速更新!
阿德里安

4

基于bažmegakapa解决方案的纯JS解决方案,并进行了一些清理,以考虑尝试提供小于元素的lineHeight的height / max-height的人员:

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

这是非常无效的代码。顺便说一下,使用“ while”外观是无限循环的潜在错误。
WebBrother

4

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

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

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


请分享您解决方案的重要部分,关于SO的链接仅是不允许的。
卡帕

最好的方面是文本本身不会被截断,因此,如果用户将表复制粘贴,则会显示整个内容。
2014年

一个非常好的概念。在本文中也提到了这一点(“淡出”方式),我相信css-tricks.com/line-clampin
Adrien是

4

这是完成此操作的纯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>

3

您可以将-webkit-line-clamp属性与一起使用div

-webkit-line-clamp: <integer>这意味着在截断内容之前设置最大行数,然后(…)在最后一行的末尾显示省略号。

div {
  width: 205px;
  height: 40px;
  background-color: gainsboro;
  overflow: hidden;
  display: -webkit-box;
  -webkit-box-orient: vertical;
  
  /* <integer> values */
  -webkit-line-clamp: 2;
}
<div>This is a multi-lines text block, some lines inside the div, while some outside</div>


2
不知道为什么有人拒绝了这个答案。截至2020年3月的浏览器支持相当不错-95%caniuse.com/#search=line
Yulian

2

这是您可以在紧急情况下使用的原始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) + '&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>

您可以在下面的代码栏中使用它。尝试在CSS面板中更改字体大小,然后在HTML面板中进行较小的编辑(例如,在某处添加额外的空间)以更新结果。无论字体大小如何,中间段落都应始终截断为传递给limitLines()的第二个参数中的行数。

Codepen: http ://codepen.io/thdoan/pen/BoXbEK


2

编辑:遇到了Shave,这是一个JS插件,可以很好地基于给定的max-height进行多行文本截断。它使用二进制搜索来找到最佳断点。绝对值得调查。


原始答案:

对于这个问题,我不得不想出一个普通的JS解决方案。就我以前的工作而言,我必须将一个长的产品名称设置为有限的宽度并超过两行。如果需要,用省略号将其截断。

我使用了各种SO帖子中的答案来制作适合我需求的内容。该策略如下:

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

PS:

  1. 如果截断仅在一行上,那么使用text-overflow的纯CSS方法:省略号会更整洁
  2. 没有固定宽度的字体可能会导致截断发生得太早或太晚(因为不同的字符具有不同的宽度)。在某些情况下,使用pad参数可以缓解这种情况,但并非万无一失:)
  3. 取回笔记本电脑后,将在原始帖子中添加链接和引用(需要历史记录)

PPS:刚刚意识到这与@DanMan和@ st.never建议的方法非常相似。检出代码片段以获取实现示例。


2

非常简单的javascript解决方案。Divs必须设置为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 + "…";
  }
}

1

这个问题的答案不是确切的,但是当我尝试做一个非常相似的页面时却遇到了这个页面,但是我想添加一个链接来“查看更多”而不是简单的省略号。这是一个jQuery函数,它将为溢出容器的文本添加“更多”链接。我个人在Bootstrap上使用它,但是如果没有它,它当然可以工作。

示例更多屏幕截图

若要使用,请按照以下步骤将文本放入容器中:

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

添加以下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
                ('<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


<sigh>我以为有人可能会对此表示反对,大概是因为这并不是问题的确切答案。尽管如此,我希望有人会发现它有用,因为我无法在其他任何地方获得此信息,而这就是我搜索后结束的地方。
Andy Beverley 2014年

1

提到的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>

1

纯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);

1

也许已经很晚了,但是使用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,FF 渲染结束时有些冷淡

火狐浏览器

在此处输入图片说明

在此处输入图片说明


1

Adrien Be的答案中找到了这个仅CSS的简短解决方案:

.line-clamp {
  display: -webkit-box;
  -webkit-line-clamp: 3;
  -webkit-box-orient: vertical; 
  overflow: hidden; 
}

截至2020年3月 浏览器的支持95.3% ,而不是在IE浏览器和Opera Mini的支撑。适用于Chrome,Safari,Firefox和Edge。


0

如果没有像Courier这样的固定宽度字体,您可能无法(当前?)进行操作。使用固定宽度的字体时,每个字母都占据相同的水平空间,因此您可以对字母进行计数,然后将结果乘以当前字体大小(以ems或exs为单位)。然后,您只需要测试一行中可以容纳多少个字母,然后将其分解即可。

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


0

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

或者,您可以采用最坏的情况,并使用字母“ W”的宽度(我认为这是最宽的)。这消除了上面的问题1,但加剧了问题2。

一种不同的方法可能是:留overflow: clip在div中并添加带有float: right; position: relative; bottom: 0px;(未嵌套)的省略号部分(可能是另一个div或图像)。诀窍是使图像显示在文本末尾上方。

您也只能在知道图像将要溢出时(例如,大约100个字符后)显示图像


什么overflow: clip啊 您希望CSS与之float一起做什么?
卡帕2012年

0

使用此代码,如果元素的高度受max-height样式限制,则不需要额外的wrapper 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);
});

还将原始文本保存在只能使用样式显示的数据属性中。鼠标悬停在:

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

1
这通常是无限循环。
Atadj

0

在我的场景中,我无法使用上述任何功能,而且我还需要告诉该功能显示多少行,而不管字体大小或容器大小如何。

我根据我的使用的解决方案Canvas.measureText方法(whic是HTML5功能)的说明这里通过多米,所以它不是完全的跨浏览器。

您可以看到它如何在这种提琴上起作用。

这是代码:

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将是这样的:

<div class="block-with-ellipsis" data-line-count="2">
    VERY LONG TEXT THAT I WANT TO BREAK IN LINES. VERY LONG TEXT THAT I WANT TO BREAK IN LINES.
</div>

获取字体系列的代码非常简单,在我的情况下,它可以工作,但是对于更复杂的场景,您可能需要沿这些方向使用一些内容

另外,就我而言,我告诉函数使用多少行,但是您可以根据容器的大小和字体来计算要显示的行数。


0

我制作了一个保留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示例


0

我写了一个解决这个问题的角度组件。它将给定的文本拆分为span元素。渲染后,它将删除所有溢出元素,并将省略号放在最后一个可见元素之后。

用法示例:

<app-text-overflow-ellipsis [text]="someText" style="max-height: 50px"></app-text-overflow-ellipsis>

Stackblitz演示:https ://stackblitz.com/edit/angular-wfdqtd

组件:

import {
  ChangeDetectionStrategy,
  ChangeDetectorRef,
  Component,
  ElementRef, HostListener,
  Input,
  OnChanges,
  ViewChild
} from '@angular/core';

@Component({
  changeDetection: ChangeDetectionStrategy.OnPush,
  selector: 'app-text-overflow-ellipsis',
  template: `
    <span *ngFor="let word of words; let i = index" [innerHTML]="word + (!endsWithHyphen(i) ? ' ' : '')"></span>
    <span #ellipsis [hidden]="!showEllipsis && !initializing" [class.initializing]="initializing" [innerHTML]="'...' + (initializing ? '&nbsp;' : '')"></span>
  `,
  styles: [`
    :host {
      display: block; 
      position: relative;
    }
    .initializing {
      opacity: 0;
    }
  `
  ]
})

export class TextOverflowEllipsisComponent implements OnChanges {
  @Input()
  text: string;

  showEllipsis: boolean;
  initializing: boolean;

  words: string[];

  @ViewChild('ellipsis')
  ellipsisElement: ElementRef;

  constructor(private element: ElementRef, private cdRef: ChangeDetectorRef) {}

  ngOnChanges(){
    this.init();
  }

  @HostListener('window:resize')
  init(){
    // add space after hyphens
    let text = this.text.replace(/-/g, '- ') ;

    this.words = text.split(' ');
    this.initializing = true;
    this.showEllipsis = false;
    this.cdRef.detectChanges();

    setTimeout(() => {
      this.initializing = false;
      let containerElement = this.element.nativeElement;
      let containerWidth = containerElement.clientWidth;
      let wordElements = (<HTMLElement[]>Array.from(containerElement.childNodes)).filter((element) =>
        element.getBoundingClientRect && element !== this.ellipsisElement.nativeElement
      );
      let lines = this.getLines(wordElements, containerWidth);
      let indexOfLastLine = lines.length - 1;
      let lineHeight = this.deductLineHeight(lines);
      if (!lineHeight) {
        return;
      }
      let indexOfLastVisibleLine = Math.floor(containerElement.clientHeight / lineHeight) - 1;

      if (indexOfLastVisibleLine < indexOfLastLine) {

        // remove overflowing lines
        for (let i = indexOfLastLine; i > indexOfLastVisibleLine; i--) {
          for (let j = 0; j < lines[i].length; j++) {
            this.words.splice(-1, 1);
          }
        }

        // make ellipsis fit into last visible line
        let lastVisibleLine = lines[indexOfLastVisibleLine];
        let indexOfLastWord = lastVisibleLine.length - 1;
        let lastVisibleLineWidth = lastVisibleLine.map(
          (element) => element.getBoundingClientRect().width
        ).reduce(
          (width, sum) => width + sum, 0
        );
        let ellipsisWidth = this.ellipsisElement.nativeElement.getBoundingClientRect().width;
        for (let i = indexOfLastWord; lastVisibleLineWidth + ellipsisWidth >= containerWidth; i--) {
          let wordWidth = lastVisibleLine[i].getBoundingClientRect().width;
          lastVisibleLineWidth -= wordWidth;
          this.words.splice(-1, 1);
        }


        this.showEllipsis = true;
      }
      this.cdRef.detectChanges();

      // delay is to prevent from font loading issues
    }, 1000);

  }

  deductLineHeight(lines: HTMLElement[][]): number {
    try {
      let rect0 = lines[0][0].getBoundingClientRect();
      let y0 = rect0['y'] || rect0['top'] || 0;
      let rect1 = lines[1][0].getBoundingClientRect();
      let y1 = rect1['y'] || rect1['top'] || 0;
      let lineHeight = y1 - y0;
      if (lineHeight > 0){
        return lineHeight;
      }
    } catch (e) {}

    return null;
  }

  getLines(nodes: HTMLElement[], clientWidth: number): HTMLElement[][] {
    let lines = [];
    let currentLine = [];
    let currentLineWidth = 0;

    nodes.forEach((node) => {
      if (!node.getBoundingClientRect){
        return;
      }

      let nodeWidth = node.getBoundingClientRect().width;
      if (currentLineWidth + nodeWidth > clientWidth){
        lines.push(currentLine);
        currentLine = [];
        currentLineWidth = 0;
      }
      currentLine.push(node);
      currentLineWidth += nodeWidth;
    });
    lines.push(currentLine);

    return lines;
  }

  endsWithHyphen(index: number): boolean {
    let length = this.words[index].length;
    return this.words[index][length - 1] === '-' && this.words[index + 1] && this.words[index + 1][0];
  }
}


-2

不确定这是否是您要查找的内容,它使用min-height而不是height。

    <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>

4
问题是代码中的数字63,如果知道该数字,那么一切都会变得容易,只有截断函数才能完成此工作,就像您的代码一样。但是,如何知道数字?换句话说,如何知道文本将在何处换行?如果可以回答此问题,则可以简单地以“ 1,计算数字; 2,截断”的逻辑来解决问题
Edward

-3

很简单的func就可以了。

指示:

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

视图:

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

3
正如我们在其他答案中已经讨论的那样,您的代码中的问题是数字36。除了使您的代码特定于特定的容器宽度之外,它也不是准确的:对于没有固定宽度的字体,字母之间可能会有很大的差异。参见iiiiiiiiiivs MMMMMMMMMM(当前字体不是:D可见)。
卡帕
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.