省略号在文本中间(Mac风格)

时间:2009-05-06 20:21:20

标签: javascript jquery css truncation

我需要在可调整大小的元素中的文本中间实现省略号("...")。 Here可能是它的样子。所以,

"Lorem ipsum dolor sit amet. Ut ornare dignissim ligula sed commodo."

变为

"Lorem ipsum dolor sit amet ... commodo."

当元素伸展到文本的宽度时,我希望省略号消失。怎么办呢?

16 个答案:

答案 0 :(得分:27)

在HTML中,将完整值放在自定义data- *属性中,如

<span data-original="your string here"></span>

然后将loadresize个事件侦听器分配给JavaScript函数,该函数将读取原始数据属性并将其放在span标记的innerHTML中。以下是省略号函数的示例:

function start_and_end(str) {
  if (str.length > 35) {
    return str.substr(0, 20) + '...' + str.substr(str.length-10, str.length);
  }
  return str;
}

调整值,或者如果可能,使它们动态化,如果需要,可以使它们成为不同的对象。如果您有来自不同浏览器的用户,则可以使用dom中其他位置的相同字体和大小从文本中窃取参考宽度。然后插入适当数量的字符以供使用。

提示也要在...上添加一个abbr-tag,或者使用户能够获得完整字符串的工具提示的消息。

<abbr title="simple tool tip">something</abbr>

答案 1 :(得分:20)

我想提出解决这个问题的例子。

主要思想是将文本分成两个偶数部分(或者第一个更大,如果长度是奇数),其中一个最后有省略号,另一个右对齐text-overflow: clip

所以你需要用js做的,如果你想让它自动/通用 - 就是分割字符串和设置属性。

但是,它有一些缺点。

  1. 没有很好的文字包装,甚至是字母(text-overflow: ''目前仅适用于FF)
  2. 如果在单词之间发生分裂 - 空格应该在第一部分。否则,它将被折叠。
  3. 由于direction: rtl,字符串的末尾不应有任何感叹号 - 它们将被移动到字符串的左侧。我认为,可以通过在::after伪元素中的标记和感叹号中放置单词的正确部分来解决此问题。但我还没有正常工作。
  4. 但是,对于所有这些,它看起来真的很酷,特别是当您拖动浏览器的边框时,您可以轻松地在jsfiddle页面上执行此操作:https://jsfiddle.net/extempl/93ymy3oL/。 或者只是运行下面固定最大宽度的代码段。

    扰流板下的Gif:

      

    Gif

    body {
      max-width: 400px;
    }
    
    span::before, span::after {
      display: inline-block;
      max-width: 50%;
      overflow: hidden;
      white-space: pre;
    }
    
    span::before {
      content: attr(data-content-start);
      text-overflow: ellipsis;
    }
    
    span::after {
      content: attr(data-content-end);
      text-overflow: '';
      direction: rtl;
    }
    <span data-content-start="Look deep into nature, and then you " 
          data-content-end=  "will understand everything better"></span>
    
    <br>
    <span data-content-start="https://www.google.com.ua/images/branding/g" 
          data-content-end=  "ooglelogo/2x/googlelogo_color_272x92dp.png"></span>

答案 2 :(得分:9)

所以我的同事提出了一个不使用额外dom元素的解决方案。我们检查div是否溢出并添加最后n个字符的数据属性。其余的都在css中完成。

这是一些HTML:

<div class="box">
    <div class="ellipsis" data-tail="some">This is my text it is awesome</div>
</div>
<div class="box">
    <div class="ellipsis">This is my text</div>
</div>

和css:

.box {
    width: 200px;
}

.ellipsis:before {
    float: right;
    content: attr(data-tail);
}

.ellipsis {
    white-space: nowrap;
    text-overflow: ellipsis;
    overflow: hidden;
}

这是强制性的jsfiddle: http://jsfiddle.net/r96vB/1/

答案 3 :(得分:6)

以下Javascript函数将执行中间截断,如OS X:

function smartTrim(string, maxLength) {
    if (!string) return string;
    if (maxLength < 1) return string;
    if (string.length <= maxLength) return string;
    if (maxLength == 1) return string.substring(0,1) + '...';

    var midpoint = Math.ceil(string.length / 2);
    var toremove = string.length - maxLength;
    var lstrip = Math.ceil(toremove/2);
    var rstrip = toremove - lstrip;
    return string.substring(0, midpoint-lstrip) + '...' 
    + string.substring(midpoint+rstrip);
}       

它将用省略号替换中间的字符。我的单元测试显示:

var s = '1234567890';
assertEquals(smartTrim(s, -1), '1234567890');
assertEquals(smartTrim(s, 0), '1234567890');
assertEquals(smartTrim(s, 1), '1...');
assertEquals(smartTrim(s, 2), '1...0');
assertEquals(smartTrim(s, 3), '1...90');
assertEquals(smartTrim(s, 4), '12...90');
assertEquals(smartTrim(s, 5), '12...890');
assertEquals(smartTrim(s, 6), '123...890');
assertEquals(smartTrim(s, 7), '123...7890');
assertEquals(smartTrim(s, 8), '1234...7890');
assertEquals(smartTrim(s, 9), '1234...67890');
assertEquals(smartTrim(s, 10), '1234567890');
assertEquals(smartTrim(s, 11), '1234567890');

答案 4 :(得分:3)

你不能用CSS做到这一点。问题是HTML和CSS应该在各种浏览器和字体中工作,几乎不可能以一致的方式计算字符串的宽度。这是idea,可能会对您有所帮助。但是,您需要多次这样做,直到找到具有适当宽度的字符串。

答案 5 :(得分:3)

这可能在游戏中有点晚了,但我想找到一个解决方案,一位同事建议一个非常优雅的,我将分享。它需要一些JS,但不是很多。

想象一下,你需要一个div大小的标签:

<div style="width: 200px; overflow: hidden"></div>

现在,你有一个函数,它将采用两个参数:一个带有标签的字符串和一个DOM元素(这个div)以使其适合:

function setEllipsisLabel(div, label) 

您要做的第一件事是创建一个带有此标签的span,并将其放入div

var span = document.createElement('span');
span.appendChild(document.createTextNode(label));
span.style.textOverflow = 'ellipsis';
span.style.display = 'inline-block';
div.appendChild(span);

我们将text-overflow属性设置为“省略号”,以便在文本被删除时,在末尾添加一个漂亮的“...”来说明这一点。我们还将display设置为“内联块”,以便这些元素具有我们稍后可以操作的实际像素尺寸。到目前为止,我们无法用纯CSS做任何事情。

但是我们想要省略号。首先,我们应该知道我们是否需要它...这可以通过比较div.clientWidthspan.clientWidth来完成 - 只有在span宽于{{div时才需要省略号。 1}}。

如果我们确实需要一个省略号,那么我们首先要说我们想要在单词末尾显示固定数量的字符 - 比如10.所以让我们创建一个只包含标签最后10个字符的span,并且进入div:

var endSpan = document.createElement('span');
endSpan.style.display = 'inline-block';
endspan.appendChild(document.createTextNode(label.substring(label.length - 10)));
div.appendChild(endSpan);

现在,让我们覆盖原始span的宽度以适应新的宽度:

span.style.width = (div.clientWidth - endSpan.clientWidth) + 'px';

因此,我们现在有一个看起来像这样的DOM结构:

<div style="width: 200px; overflow: hidden">
   <span style="display: inline-block; text-overflow: ellipsis; width: 100px">
      A really long label is shown in this span
   </span>
   <span style="display: inline-block"> this span</span>
</div>

因为第一个spantext-overflow设置为“省略号”,所以最后会显示“...”,然后是第二个跨度的10个字符,从而显示省略号大约在div的中间。

你也不需要对endSpan的10个字符长度进行硬编码:这可以通过计算span的初始宽度与div的宽度的比率来近似,减去相应的从标签长度开始的比例除以2。

答案 6 :(得分:2)

经过对弹性盒子的一些研究后,我发现这个纯CSS解决方案,我相信这很酷。

<div style="width:100%;border:1px solid green;display:inline-flex;flex-wrap:nowrap;">
   <div style="flex: 0 1 content;text-overflow: ellipsis;overflow:hidden;white-space:nowrap;"> Her comes very very very very very very very very very very very very very very very very very very very long </div>
   <div style="flex: 1 0 content;white-space:nowrap;"> &nbsp;but flexible line</div>
</div>

答案 7 :(得分:1)

这是我能找到的最短的一位用......取代中间的3个字符。

function shorten(s, max) {
  return s.length > max ? s.substring(0, (max / 2) - 1) + '...' + s.substring(s.length - (max / 2) + 2, s.length) : s
}

答案 8 :(得分:1)

此解决方案是上述解决方案的组合,将最后一个完整的单词放在缩短的文本的末尾。但是,如果最后一个单词的长度大于可用空间的三分之一,则该单词也会从左侧缩短。如果找到破折号(“-”),则将其剪切掉,如果没有,则将其剪切掉。

function truncate(text, textLimit) {
    if (!text) return text;
    if (textLimit < 1) return string;
    if (text.length < textLimit) return text;
    if (textLimit === 1) return text.substring(0,1) + '...';
    /* extract the last word */
    var lastPart = text.slice( string.lastIndexOf(' ')+1 );
    /* if last word is longer then a third of the max available space
       cut it from the left */
    var lastPartLimit = Math.ceil(textLimit / 3);
    if(lastPart.length > lastPartLimit) {
        var truncatedLastPart = lastPart;
        /* Try to find a dash and cut the last word there */
        var lastDashPart = text.slice( text.lastIndexOf('-')+1 );
        if(lastDashPart.length < lastPartLimit){
            truncatedLastPart = lastDashPart;
        }
        /* If the last part is still to long or not available cut it anyway */
        if(truncatedLastPart.length > lastPartLimit) {
            var lastIndex = lastPart.length - lastPartLimit;
            truncatedLastPart = lastPart.substring( lastIndex );
        }
        lastPart = truncatedLastPart;
    }
    var dots = '... ';
    var firsPartLength = textLimit - lastPart.length - dots.length;
    return text.substring(0, firstPartLength) + dots + lastPart;
}

console.log( truncate("New York City", 10) ); // Ne... City (max of 10 characters)
console.log( truncate("New York Kindergarden", 14) ); // Ne...ergarden (max of 14 characters, last word gets cut from the left by a third)
console.log( truncate("New York Kinder-garden", 14) ); // Ne...garden (max of 14 characters, last word gets cut by the dash from the left)

答案 9 :(得分:0)

我刚创建了一个可以在中间,近端和末端修剪的功能,但还没有经过测试,因为我最终需要在服务器端

//position acceptable values : middle, end, closeEnd
function AddElipsis(input, maxChars, position) {
    if (typeof input === 'undefined') {
        return "";
    }
    else if (input.length <= maxChars) {
        return input;
    }
    else {
        if (position == 'middle') {
            var midPos = Math.floor(maxChars / 2) - 2;
            return input.substr(0, midPos) + '...' + input.substr(input.length - midPos, input.length);
        }
        else if (position == 'closeEnd') {
            var firstPart = Math.floor(maxChars * 0.80) - 2;
            var endPart = Math.floor(maxChars * 0.20) - 2;
            return input.substr(0, firstPart) + '...' + input.substr(input.length - endPart, input.length);
        }
        else {
            return input.substr(0, maxChars - 3) + '...';
        }
    }
}

答案 10 :(得分:0)

另一个刺:

function truncate( str, max, sep ) {
    max = max || 10;
    var len = str.length;
    if(len > max){
        sep = sep || "...";
        var seplen = sep.length;
        if(seplen > max) { return str.substr(len - max) }

        var n = -0.5 * (max - len - seplen);
        var center = len/2;
        return str.substr(0, center - n) + sep + str.substr(len - center + n);
    }
    return str;
}

console.log( truncate("123456789abcde") ); // 123...bcde (using built-in defaults) 
console.log( truncate("123456789abcde", 8) ); // 12...cde (max of 8 characters) 
console.log( truncate("123456789abcde", 12, "_") ); // 12345_9abcde (customize the separator) 

答案 11 :(得分:0)

这将使您可以更好地控制省略号和占位符文本的位置:

function ellipsis(str, maxLength, ellipsisLocationPercentage,placeholder) {
    /*
    ARGUMENTS:
    str - the string you want to maninpulate
    maxLength -  max number of characters allowed in return string
    ellipsisLocationPercentage (optional) - How far (percentage wise) into the return string you want the ellipses to be placed
        Examples:
        .85 : This is a very long string. This is a very long string. This is a very long string. This is a ver[...]very long string.
        .25 : This is a very long string. [...]g. This is a very long string. This is a very long string. This is a very long string.
    placeholder (optional) - this will be used to replace the removed substring. Suggestions : '...', '[..]', '[ ... ]', etc....
    */
    if(ellipsisLocationPercentage == null || isNaN(ellipsisLocationPercentage) || ellipsisLocationPercentage >= 1 || ellipsisLocationPercentage <= 0){
        //we've got null or bad data.. default to something fun, like 85% (that's fun, right??)
        ellipsisLocationPercentage = .85;
    }
    if(placeholder == null || placeholder ==""){
        placeholder = "[...]";
    }

    if (str.length > (maxLength-placeholder.length)) {
        //get the end of the string
        var beginning = str.substr(0, (maxLength - placeholder.length)*ellipsisLocationPercentage );
        var end = str.substr(str.length-(maxLength - placeholder.length) * (1-ellipsisLocationPercentage));
        return beginning + placeholder + end;
    }
    return str;
}

您可以致电:

来调用此功能
ellipsis("This is a very long string. Be Scared!!!!", 8);//uses default values
ellipsis("This is a very long string. Be Scared!!!!", 8,.5);//puts ellipsis at half way point
ellipsis("This is a very long string. Be Scared!!!!", 8,.75,'<..>');//puts ellipsis at 75% of the way into the string and uses '<..>' as the placeholder

答案 12 :(得分:0)

为了做一个干净的剪辑,并在缩短文本的末尾有一个完整的单词,我使用了以下功能。

function prepareText(text){
  var returnString = text;
  var textLimit = 35;
  if(text.length > textLimit){
    var lastWord = text.slice( text.lastIndexOf(' ')+1 );
    var indexFromEnd = lastWord.length;
    var ellipsis = '... ';

    returnString = text.slice(0, textLimit - indexFromEnd - ellipsis.length);
    returnString = returnString + ellipsis + lastWord;
  }
  return returnString;
}

$('#ex1Modified').html( prepareText( $('#ex1').html() ) );

$('#ex2Modified').html( prepareText( $('#ex2').html() ) );

$('#ex3Modified').html( prepareText( $('#ex3').html() ) );
body{color:#777; font-family: sans-serif;}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>

<h2>Shortened Quotes from Albert Einstein</h2>

<div id="ex1">"The true sign of intelligence is not knowledge but imagination."</div>
<div id="ex1Modified"></div>
<br>
<div id="ex2">"Look deep into nature, and then you will understand everything better."</div>
<div id="ex2Modified"></div>
<br>
<div id="ex3">"You can't blame gravity for falling in love."</div>
<div id="ex3Modified"></div>

答案 13 :(得分:0)

这是一个优雅的解决方案:

function truncateMiddle(word) {
    const tooLongChars = 15; // arbitrary

    if (word.length < tooLongChars) {
        return word;
    }

    const ellipsis = '...';
    const charsOnEitherSide = Math.floor(tooLongChars / 2) - ellipsis.length;

    return word.slice(0, charsOnEitherSide) + ellipsis + word.slice(-charsOnEitherSide);
}

答案 14 :(得分:0)

我在这里看到的所有解决方案都没有考虑到不同字符的宽度不同。 我的解决方案考虑了这一点。基本上,它将文本删除一个字符,直到适合为止,看看:

const span = document.getElementById("span");
const div = document.getElementById("div");
const originalText = span.textContent;
const textLength = originalText.length;
let part1 = originalText.substr(0, Math.floor(textLength/2));
let part2 = originalText.substr(Math.floor(textLength/2));
let trimPart1 = true;
while (span.clientWidth > div.clientWidth) {
    if (trimPart1) {
    part1 = part1.substr(0, part1.length - 1);
  } else {
    part2 = part2.substr(-1 * (part2.length - 1));
  }
    span.textContent = part1 + "..." + part2;
  trimPart1 = !trimPart1;
}
<div id="div" style="overflow: hidden; width: 200px; white-space: nowrap;">
  <span id="span" style="display: inline-block">this is a quite long text that has some words and I want it to be split in half</span>
</div>

https://jsfiddle.net/maxim_mazurok/oujctpz8/56/

Mac的Finder以相同的方式工作,它首先尝试剥离左侧部分,然后剥离右侧部分。因此,就像我的解决方案一样,它可能有WWWW...WWWWW

虽然它不是最有效的一种。也许,使用虚拟DOM或canvas可以更好地优化性能。

答案 15 :(得分:0)

这是我的看法 - 一个仅适用于 CSS 的解决方案,遗憾的是目前仅适用于 Firefox:

div {
  width: 20em;
  overflow: hidden;
  white-space: nowrap;
  text-overflow: ellipsis;
  text-overflow: " … is also your text.";
}
<div>Here's the long string of letters that accidentally is also your text.</div>

如果您需要动态文本,您可以直接在元素上指定第二个 text-overflow 声明。不支持这种语法的浏览器(Chrome,特别是 :-)将回退到普通的旧省略号。