【问题标题】:Ellipsis in the middle of a text (Mac style)文本中间的省略号(Mac 样式)
【发布时间】:2010-10-24 07:28:43
【问题描述】:

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

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

变成

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

当元素被拉伸到文本的宽度时,我希望省略号消失。如何做到这一点?

【问题讨论】:

  • 如果你有它,我很想看看你的最终实现。 :)

标签: javascript jquery css truncation


【解决方案1】:

在 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 中以相同的字体和大小从文本中窃取参考宽度。然后插入适当数量的字符以供使用。

提示也是在 ... 或 who 消息上有一个缩写标签,以使用户能够获得包含完整字符串的工具提示。

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

【讨论】:

  • 这最终成为我最终解决方案的最佳基础。加上几行额外的 JavaScript 代码,它就完全符合我的要求。我决定使用“标题”而不是自定义标签,所以现在它自然地提供了可访问性。感谢 Stefan、John 和 Kgiannakakis!
  • @user102465 可以分享一下最终结果吗?谢谢!
  • 只有css方法吗?在 UI 本身中修复它而不是使用 javsacript?
  • 第二部分实际上可以使用str.substr(-10)
【解决方案2】:

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

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

因此,如果您想让 js 自动/通用,您需要做的就是拆分字符串并设置属性。

不过,它也有一些缺点。

  1. 没有很好的文字,甚至字母包装(text-overflow: '' 目前仅在 FF 中有效)
  2. 如果单词之间发生拆分 - 空格应该在第一部分。否则,它将被折叠。
  3. 字符串结尾不应有任何感叹号,因为direction: rtl - 它们将被移到字符串的左侧。我认为,可以通过将单词的右侧部分放入标签中并将感叹号放入::after 伪元素中来解决此问题。但我还没有让它正常工作。

但是,有了所有这些,它对我来说真的很酷,尤其是当你拖动浏览器的边框时,你可以在 jsfiddle 页面上轻松做到这一点:https://jsfiddle.net/extempl/93ymy3oL/。 或者只运行下面固定最大宽度的 sn-p。

剧透下的动图:

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>

【讨论】:

  • 对于 chrome,text-overflow: ''; 是否有解决方法?不支持将字符串作为值;
  • @jaysonder 不幸的是,到目前为止还没有纯 CSS 的解决方法。它仍然只在 FF 中有效:developer.mozilla.org/en-US/docs/Web/CSS/…
  • 上面的 sn-p 似乎在 chrome 中运行良好,尽管后半部分的文本剪辑看起来有点滑稽。
【解决方案3】:

所以我的同事想出了一个不使用额外 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/

【讨论】:

  • 非常好的解决方案,但不幸的是它在 Firefox 34(文本重叠)和 IE
  • 我喜欢这个解决方案。适用于 Safari (mac)、FF 57、Edge 和 Chrome 66。
  • 差不多,但是每次box宽度变化都需要执行JS,否则:after内容卡住:(
【解决方案4】:

以下 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');

【讨论】:

  • 这很好,可以按描述工作,但是我需要使输出字符串“可拉伸”,以便根据一个人的视口大小确定截断。大屏幕 - 无截断,窄屏幕 - 使用动态计算的字符数截断字符串以实现最佳拟合。
  • 您必须将一个事件处理程序附加到其容器,然后它将计算与容器宽度属性相关的适当的 maxLength。如果您的字体系列是等宽字体,这将很容易;如果成比例,那么您需要进行试验以获得正确的启发式。
  • 要指出的是,这仅适用于固定宽度的字体显示。在可变宽度字体上,文本的显示长度与字符长度并不精确相关。
【解决方案5】:

这可能有点晚了,但我一直在寻找解决方案,一位同事提出了一个非常优雅的解决方案,我将分享。它需要一些 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 设置为“inline-block”,以便这些元素具有我们以后可以操作的真实像素尺寸。到目前为止,没有什么是我们用纯 CSS 做不到的。

但是我们想要中间的省略号。首先,我们应该确定是否需要它...这可以通过比较 div.clientWidthspan.clientWidth 来完成 - 仅当 spandiv 宽时才需要省略号。

如果我们确实需要省略号,让我们首先说我们希望在单词末尾显示固定数量的字符 - 比如说 10。所以让我们创建一个仅包含标签最后 10 个字符的跨度,并坚持将其放入 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 的初始宽度的比率来近似,从长度中减去适当的比例标签和除以二。

【讨论】:

    【解决方案6】:

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

    【讨论】:

    【解决方案7】:

    在对 flex box 进行一些研究后,我发现了这个纯 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>
    

    【讨论】:

    • 不要认为这回答了问题。这不能解决在 1 字符串中间添加省略号的问题。这只是在 2 个字符串之间添加一个省略号。即,在@user102465 的场景中,首先必须以某种方式拆分字符串才能使您的解决方案正常工作。
    【解决方案8】:

    这是我能找到的最短的位,它将中间的 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
    }
    

    【讨论】:

      【解决方案9】:

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

      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 或画布来更好地优化性能。

      【讨论】:

        【解决方案10】:

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

        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)
        

        【讨论】:

          【解决方案11】:

          这是我的看法 - 一个纯 CSS 的解决方案,遗憾的是目前只能在 Firefox 中使用:

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

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

          【讨论】:

            【解决方案12】:

            我刚刚创建了一个可以在中间、nearEnd 和 End 修剪的函数,但还没有测试,因为我终于在服务器端需要它了

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

            【讨论】:

              【解决方案13】:

              另一个刺:

              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) 
              

              【讨论】:

                【解决方案14】:

                这将使您对省略号和占位符文本的位置有更多的控制:

                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
                

                【讨论】:

                  【解决方案15】:

                  为了简洁明了并在缩短的文本末尾添加一个完整的单词,我使用了以下函数。

                  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>

                  【讨论】:

                    【解决方案16】:

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

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

                    【讨论】:

                      猜你喜欢
                      • 1970-01-01
                      • 2013-02-10
                      • 2011-06-05
                      • 1970-01-01
                      • 2020-01-20
                      • 1970-01-01
                      • 2018-07-22
                      • 1970-01-01
                      • 1970-01-01
                      相关资源
                      最近更新 更多