文字中的省略号(Mac 风格)

71

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

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

变成

"Lorem ipsum dolor sit amet ... commodo."
当元素被拉伸至文本宽度时,我希望省略号消失。如何实现?

7
如果你有最终实现的话,我很乐意看一下。 :) - Paolo Bergantino
17个回答

2
[编辑] 直到其他浏览器支持text-overflow的字符串值,这是仅适用于Firefox的解决方案; 参见 https://caniuse.com/mdn-css_properties_text-overflow_string
这是一个相当复杂的解决方案,它使用JavaScript来修改元素上的textOverflow样式属性,因此可以回退到现有的CSS(如果元素后来扩展,省略号将消失)。
在计算中点时,它考虑了字符的不同宽度,通过绕过字符本身,而是查看这些字符上的文本选择的宽度。
与我迄今为止看到的其他解决方案(除了Ale的解决方案)不同,它实际上并不干扰DOM文本内容本身,而是将内容的尾部复制到CSS中,因此屏幕阅读器等应该不受影响。
我设置了最大高度为2em,以演示多行段落的工作原理,但这一部分是可选的。
一个待办事项是,如果元素的宽度发生变化,您需要重新运行applyMidOverflow函数(可以通过操作下面演示中右下角的调整大小控件来观察到)。

function applyMidOverflow(el, delimiter) {
    if (delimiter === undefined || 
        Number.isInteger(delimiter)  // forEach index
       ) {
        var cs = getComputedStyle(el);     
        if (cs.textOverflow === 'ellipsis' || cs.textOverflow === '') {
            delimiter = '…';
        } else {
            // remove quotes
            delimiter = s.textOverflow.substring(1, s.textOverflow.length - 1)
        }
    }
    var r = el.getBoundingClientRect();
    var half_width_pos = r.x + (r.width/2);    
    if (el.childNodes.length !== 1 || el.childNodes[0].nodeType !== 3) {
        console.warn('midOverflow: need a single TEXT_NODE child', el);
        return;
    }    
    const textChild = el.childNodes[0];
    var range = document.createRange();    
    var end = textChild.textContent.length;

    // set the following to zero to be sure
    var approx_mid = Math.round(end * 0.4);

    for (var i = approx_mid; i < end; i++) {
        // TODO: binary search
        range.setStart(textChild, i);
        range.setEnd(textChild, end);
        // not getBoundingClientRect as word could wrap
        var rects = range.getClientRects();
        var selected_t = Array.from(rects, (r)=>r.width).reduce((a, b)=>a+b, 0);
        if (selected_t < half_width_pos) {
            break;   
        }        
    }   
    el.style.textOverflow = '" ' + delimiter + ' ' + textChild.textContent.substring(i).replace(/"/, '\\"').replace('\n', '').replace(/\s+$/g, '') + '"';
}

addEventListener('load', () => {
    document.querySelectorAll('.overflow-mid').forEach(applyMidOverflow);    
});
.overflow-mid {
  overflow: hidden;
  text-overflow: ellipsis; /* will be overwritten */
  white-space: nowrap;
  height: 2em;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>

<div style="resize:both;overflow:auto;width:75%">

<div class="overflow-mid">Multi line ipsum dolor amet meatball bresaola t-bone tri-tip brisket. Jowl pig picanha cupim landjaeger, frankfurter spare ribs chicken. Porchetta jowl panhttps://jsfiddle.net/amvebozn/2/#runcetta drumstick shankle cow spare ribs jerky tail kevin biltong capicola brisket venison bresaola. Flank sirloin jowl andouille meatball venison salami ground round rump boudin turkey capicola t-bone. Sirloin filet mignon tenderloin beef, biltong doner bresaola brisket shoulder pork loin shankle turducken shank cow. Ragged end of multi line.
</div>    

<div class="overflow-mid">"The true sign of intelligence is not knowledge but imagination."</div>
<br>
<div class="overflow-mid">"Albert Einstein likely didn't utter the majority of the many quotes that are attributed to him."</div>
<div class="overflow-mid">"You can't blame gravity for falling in love."</div>

</div>

https://jsfiddle.net/amvebozn/5/


我喜欢考虑到可访问性,但是SO代码片段和jsfiddle只在字符串末尾显示省略号,而不是像OP要求的那样在中间显示。 - Maxim Mazurok
1
啊,抱歉,我现在意识到我的解决方案目前只适用于Firefox(尽管它会优雅地回退);我已经更新了答案并附上了免责声明。 - EoghanM

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

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

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)

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

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

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>


0

这是我的看法 - 一种仅在Firefox中可用的纯CSS解决方案:

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)将回退到普通的省略号。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接