1. First gear: single line omission

If there is too much text in an area and the display area is limited, we choose to show only part of the text, and then show the ellipsis of 3 dots at the end. The implementation of the scheme is very simple, front-end new students can easily achieve, is used to text-overflow: ellipsis; This property.

Reference:

  • MDN: text-overflow

2. Second grade: multiple line ellipsis

Of course, there’s also the need to omit multiple lines in a business,

For example, the display of the commodity name in the commodity card requires a maximum of two lines to be displayed, and the excess content is truncated at the end of the second line, showing the ellipsis.

Multi-line ellipsis scheme is a lot, the simplest use of CSS trick: with the old version of flex layout -webkit-box, with CSS properties – Webkit-line-clamp, can easily achieve multi-line ellipsis. demo:

p {
  width: 300px;
  display: -webkit-box;
  -webkit-box-orient: vertical;
  -webkit-line-clamp: 2;
  overflow: hidden;
}
Copy the code

There are many other schemes, such as ellipsis as a separate layer over the content, to simulate the effect of ellipsis; With JS to get character positions, and even using canvas to render.

Reference:

  • MDN:-webkit-line-clamp
  • a-pure-css-solution-for-multiline-text-truncation
  • line-clampin

3. Third grade: multiple lines with ellipsis not at the end

As shown in the figure, multiple lines are omitted, and the lower right corner is not an ellipsis, but a link, and the left side of the link is the ellipsis displayed after truncation.

Unfortunately, I have not yet found a pure CSS solution that can elegantly solve this problem. I used the object Range and js to solve it in a relatively elegant way for the time being. Dom is simple, requires not much CSS, js quantity is also small, easy to encapsulate.

First, the DOM part:

<div class="ellipsis">
    <span class="text">Princess and Pea is currently the only cross-border e-commerce platform directly entered by Japanese suppliers and the exclusive agent of Japanese high-end brands.</span>
    <div class="link">
        <span>.</span>
        <a>Check the details&gt;</a>
    </div>
</div>
Copy the code

.text is what we want to display and truncate, and.link is the link at the bottom right. Notice that there is an ellipsis in front of the link, but we’ll see how useful it is in a moment.

Then CSS is used for simple layout

.ellipsis{
    position: relative;
    width: 200px;
    height: 40px;
    border: 1px solid # 000;
    line-height: 20px;
    overflow: hidden;
    font-size: 14px;
}

.link{
    position: absolute;
    right: 0;
    bottom: 0;
    color: red;
}
.link span{
    opacity: 0;
}
Copy the code

The current results are as follows

The link is in the bottom right corner, and more than two lines have been truncated. But the link overlaps with the second line of text, which needs to be truncated further to the left.

Note that the CSS shows that the ellipsis with the link, which has a transparency of 0, is not visible

My next thought is:

  1. Gets the location of the.link that can be usedelement.getBoundingClientRect()Easy access, linkRect
  2. It then checks the position of each text in. Text, called letterRect. If letterRect and linkRect intersect, then truncate the letterRect before the letterRect text. Then fill in the ellipsis after the screenshot. Because the space occupied by ellipsis is considered in link, the ellipsis can be confidently added in the final result.

So how do you get the position of each character? So that’s where the Range object comes in. The Range interface represents a fragment of a document that can contain nodes and parts of text nodes. It represents a fragment of a document that contains nodes or text nodes, and is often used in Web rich text editors.

<div id="desc">Here's a little demo text</div>
<script>
    var textNode = document.querySelector('#desc').childNodes[0];
    var range = document.createRange();
    range.setStart(textNode, 0);
    range.setEnd(textNode, 3);
</script>
Copy the code

Range above is.desc and this is a three-word text node fragment.

Also, the Range has an interesting feature: it folds. As in the example above, if the setting ends as it begins, it collapses.

    range.setStart(textNode, 1);
    range.setEnd(textNode, 1);
Copy the code

As above, when range collapses, it represents the position between the two characters in the sum.

In addition, Range itself has the getBoundingClientRect method to get the location of the document fragment. Result Range folding function and position ability, we can realize the above idea.

// Content is the text element to truncate
const content = document.querySelector('.ellipsis span');
// Its first node is a text node that can be passed to the range object
const textNode = content.childNodes[0];
const range = document.createRange();
// Get the location of the link element. Notice that it contains the ellipsis space.
const linkRect = document.querySelector('.link').getBoundingClientRect();
const text = content.innerText;
let max = 0;
for(let i=0; i<text.length; i++){// Fold range in front of a text
    range.setStart(textNode, i);
    range.setEnd(textNode, i);
    // Get the position of the fold, the position before the character
    const rect = range.getBoundingClientRect();
    // If the space is crossed with link, it must be truncated before the previous character
    if(rect.bottom > linkRect.top && rect.left>linkRect.left) {
        max = i-1;
        break; }}if(max>0) {
    textNode.textContent = text.substring(0, max)+'... ';
}
Copy the code

Advantages of the above scheme:

  1. The code and structure of the DOM are simple and do not require special DOM structures and auxiliary elements;
  2. Simple style, just simple control beyond hidden content on the line, no need for very clever CSS properties;
  3. Js finally only makes some content adjustments to the DOM, and does not change the area height, does not cause a large area of page redraw, the performance is very good

Finally implement demo, see >>

reference

  • Range