Ellipsis in the middle of a text (Mac style)

后端 未结 15 2234
长情又很酷
长情又很酷 2020-11-29 03:04

I need to implement ellipsis (\"...\") in the middle of a text within a resizable element. Here is what it might look like. So,

\"Lorem ipsum do         


        
相关标签:
15条回答
  • 2020-11-29 03:10

    This may be a bit late in the game, but I was looking to find a solution to this, and a colleague suggested a very elegant one, which I'll share. It requires some JS, but not a lot.

    Imagine you have a div of a size you need to put your label into:

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

    Now, you have a function which will take two params: a string with the label, and a DOM element (this div) to fit it into:

    function setEllipsisLabel(div, label) 
    

    The first thing you do is create a span with this label, and put it into the div:

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

    We set the text-overflow property to "ellipsis" so that as the text gets chopped off, a nice "..." is added at the end to illustrate this. We also set display to be "inline-block" so that these elements have real pixel dimensions we can manipulate later. So far, nothing we could not have done with pure CSS.

    But we want the ellipsis in the middle. First, we should find out if we need it at all... This can be done by comparing div.clientWidth to span.clientWidth - ellipsis is only needed if the span is wider than the div.

    If we do need an ellipsis, let's start by saying that we want a fixed number of characters shown at the end of the word - say 10. So let's create a span containing only the last 10 characters of the label, and stick it into the div:

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

    Now, let's override the width of the original span to accommodate the new one:

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

    As a result of this, we now have a DOM structure that looks something like this:

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

    Because the first span has text-overflow set to "ellipsis", it will show "..." at the end, followed by the 10 characters of the second span, resulting in the ellipsis showing approximately in the middle of the div.

    You don't need to hardcode the 10 character length for the endSpan either: this can be approximated by calculating ratio of the span's initial width to that of the div, subtracting the appropriate proportion from the length of the label and dividing by two.

    0 讨论(0)
  • 2020-11-29 03:12

    This will give you a little more control over the position of the ellipsis and the placeholder text:

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

    You can call this function by calling:

    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 讨论(0)
  • 2020-11-29 03:13

    In the HTML, put the full value in a custom data-* attribute like

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

    Then assign load and resize event listeners to a JavaScript function which will read the original data attribute and place it in the innerHTML of your span tag. Here is an example of the ellipsis function:

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

    Adjust the values, or if possible, make them dynamic, if necessary for different objects. If you have users from different browsers, you can steal a reference width from a text by the same font and size elsewhere in your dom. Then interpolate to an appropriate amount of characters to use.

    A tip is also to have an abbr-tag on the ... or who message to make the user be able to get a tooltip with the full string.

    <abbr title="simple tool tip">something</abbr>
    
    0 讨论(0)
  • 2020-11-29 03:14

    None of the solutions that I saw here take into account that different characters have different width. My solution takes this into account. Basically, it strips text by one character until it fits, take a look:

    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's Finder works the same way, it first tries to strip the left part, then the right part. So, it may have WWWW...WWWWW, just as my solution.

    It's not the most efficient one though. Perhaps, the same can be achieved using virtual DOM or canvas to better optimize performance.

    0 讨论(0)
  • 2020-11-29 03:15

    After some research on flex boxes I found this pure CSS solution which I believe is pretty cool.

    <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>
    
    0 讨论(0)
  • 2020-11-29 03:15

    Here's the shortest bit I could find which replaces 3 characters in the middle with ....

    function shorten(s, max) {
      return s.length > max ? s.substring(0, (max / 2) - 1) + '...' + s.substring(s.length - (max / 2) + 2, s.length) : s
    }
    
    0 讨论(0)
提交回复
热议问题