With CSS, use "..." for overflowed block of multi-lines

HtmlEllipsisCss

Html Problem Overview


with

overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;

"..." will be shown in the end of the line if overflowed. However, this will be shown only in one line. But I would like it to be shown in multi-lines.

It may looks like:

+--------------------+
|abcde feg hij   dkjd|
|dsji jdia js ajid  s|
|jdis ajid dheu d ...|/*Here it's overflowed, so "..." is shown. */
+--------------------+

Html Solutions


Solution 1 - Html

There are also several jquery plugins that deal with this issue, but many do not handle multiple lines of text. Following works:

There also some preformance tests.

Solution 2 - Html

I have hacked around until I've managed to achieve something close to this. It comes with a few caveats:

  1. It's not pure CSS; you have to add a few HTML elements. There's however no JavaScript required.
  2. The ellipsis is right-aligned on the last line. This means that if your text isn't right-aligned or justified, there may be a noticable gap between the last visible word and the ellipsis (depending on the length of the first hidden word).
  3. The space for the ellipsis is always reserved. This means that if the text fits in the box almost precisely, it may be unnecessarily truncated (the last word is hidden, although it technically wouldn't have to).
  4. Your text needs to have a fixed background color, since we're using colored rectangles to hide the ellipsis in cases where it's not needed.

I should also note that the text will be broken at a word boundary, not a character boundary. This was deliberate (since I consider that better for longer texts), but because it's different from what text-overflow: ellipsis does, I thought I should mention it.

If you can live with these caveats, the HTML looks like this:

<div class="ellipsify">
    <div class="pre-dots"></div>
    <div class="dots">&hellip;</div>
    <!-- your text here -->
    <span class="hidedots1"></span>
    <div class="hidedots2"></div>
</div>

And this is the corresponding CSS, using the example of a 150 pixel wide box with three lines of text on a white background. It assumes you have a CSS reset or similar that sets margins and paddings to zero where necessary.

/* the wrapper */
.ellipsify {
    font-size:12px;
    line-height:18px;
    height: 54px;       /* 3x line height */
    width: 150px;
    overflow: hidden;
    position: relative; /* so we're a positioning parent for the dot hiders */
    background: white;
}

/* Used to push down .dots. Can't use absolute positioning, since that
   would stop the floating. Can't use relative positioning, since that
   would cause floating in the wrong (namely: original) place. Can't 
   change height of #dots, since it would have the full width, and
   thus cause early wrapping on all lines. */
.pre-dots {
    float: right;
    height: 36px;  /* 2x line height (one less than visible lines) */
}

.dots {
    float: right; /* to make the text wrap around the dots */
    clear: right; /* to push us below (not next to) .pre-dots */
}

/* hides the dots if the text has *exactly* 3 lines */
.hidedots1 {
    background: white;
    width: 150px;
    height: 18px;       /* line height */
    position: absolute; /* otherwise, because of the width, it'll be wrapped */
}

/* hides the dots if the text has *less than* 3 lines */
.hidedots2 {
    background: white; 
    width: 150px;
    height: 54px;       /* 3x line height, to ensure hiding even if empty */
    position: absolute; /* ensures we're above the dots */
}

The result looks like this:

image of the rendered result with different text lengths

To clarify how it works, here's the same image, except that .hidedots1 is hightlighted in red, and .hidedots2 in cyan. These are the rectangles that hide the ellipsis when there's no invisible text:

the same image as above, except that the helper elements are highlighted in color

Tested in IE9, IE8 (emulated), Chrome, Firefox, Safari, and Opera. Does not work in IE7.

Solution 3 - Html

Here's a recent css-tricks article which discusses this.

Some of the solutions in the above article (which are not mentioned here) are

  1. -webkit-line-clamp and 2) Place an absolutely positioned element to the bottom right with fade out

Both methods assume the following markup:

<div class="module"> /* Add line-clamp/fade class here*/
  <p>Text here</p>
</div>

with css

.module {
  width: 250px;
  overflow: hidden;
}
  1. -webkit-line-clamp --

line-clamp FIDDLE (..for a maximum of 3 lines)

.line-clamp {
  display: -webkit-box;
  -webkit-line-clamp: 3;
  -webkit-box-orient: vertical;  
  max-height: 3.6em; /* I needed this to get it to work */
}

2) fade out

> Let's say you set the line-height to 1.2em. If we want to expose > three lines of text, we can just make the height of the container > 3.6em (1.2em × 3). The hidden overflow will hide the rest.

Fade out FIDDLE

p
{
    margin:0;padding:0;
}
.module {
  width: 250px;
  overflow: hidden;
  border: 1px solid green;
  margin: 10px;
}

.fade {
  position: relative;
  height: 3.6em; /* exactly three lines */
}
.fade:after {
  content: "";
  text-align: right;
  position: absolute;
  bottom: 0;
  right: 0;
  width: 70%;
  height: 1.2em;
  background: linear-gradient(to right, rgba(255, 255, 255, 0), rgba(255, 255, 255, 1) 50%);
}

Solution #3 - A combination using @supports

We can use @supports to apply webkit's line-clamp on webkit browsers and apply fade out in other browsers.

@supports line-clamp with fade fallback fiddle

<div class="module line-clamp">
  <p>Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. Vestibulum tortor quam, feugiat vitae, ultricies eget, tempor sit amet, ante. Donec eu libero sit amet quam egestas semper. Aenean ultricies mi vitae est. Mauris placerat eleifend leo.</p>
</div>

CSS

.module {
  width: 250px;
  overflow: hidden;
  border: 1px solid green;
  margin: 10px;
}

.line-clamp {
      position: relative;
      height: 3.6em; /* exactly three lines */
    }
.line-clamp:after {
      content: "";
      text-align: right;
      position: absolute;
      bottom: 0;
      right: 0;
      width: 70%;
      height: 1.2em;
      background: linear-gradient(to right, rgba(255, 255, 255, 0), rgba(255, 255, 255, 1) 50%);
 }

@supports (-webkit-line-clamp: 3) {
    .line-clamp {
        display: -webkit-box;
        -webkit-line-clamp: 3;
        -webkit-box-orient: vertical;  
        max-height:3.6em; /* I needed this to get it to work */
        height: auto;
    }
    .line-clamp:after {
        display: none;
    }
}

Solution 4 - Html

The link below provides a pure HTML / CSS solution to this problem.

Browser support - as stated in the article:

> So far we have tested on Safari 5.0, IE 9 (must be in standards mode), > Opera 12 and Firefox 15. > > Older browsers will still work quite well, as the meat of the layout > is in normal positioning, margin and padding properties. if your > platform is older (e.g. Firefox 3.6, IE 8), you can use the method but > redo the gradient as a standalone PNG image or DirectX filter.

http://www.mobify.com/dev/multiline-ellipsis-in-pure-css

the css:

p { margin: 0; padding: 0; font-family: sans-serif;}

.ellipsis {
    overflow: hidden;
    height: 200px;
    line-height: 25px;
    margin: 20px;
    border: 5px solid #AAA; }

.ellipsis:before {
    content:"";
    float: left;
    width: 5px; height: 200px; }

.ellipsis > *:first-child {
    float: right;
    width: 100%;
    margin-left: -5px; }		

.ellipsis:after {
    content: "\02026";  
    
    box-sizing: content-box;
    -webkit-box-sizing: content-box;
    -moz-box-sizing: content-box;
    
    float: right; position: relative;
    top: -25px; left: 100%; 
    width: 3em; margin-left: -3em;
    padding-right: 5px;
    
    text-align: right;
    
    background: -webkit-gradient(linear, left top, right top,
        from(rgba(255, 255, 255, 0)), to(white), color-stop(50%, white));
    background: -moz-linear-gradient(to right, rgba(255, 255, 255, 0), white 50%, white);			
    background: -o-linear-gradient(to right, rgba(255, 255, 255, 0), white 50%, white);
    background: -ms-linear-gradient(to right, rgba(255, 255, 255, 0), white 50%, white);
    background: linear-gradient(to right, rgba(255, 255, 255, 0), white 50%, white); }

the html:

<div class="ellipsis">
    <div>
		<p>Call me Ishmael.  Some years ago &ndash; never mind how long precisely &ndash; having little or no money in my purse, and nothing particular to interest me on shore, I thought I would sail about a little and see the watery part of the world.  It is a way I have of driving off the spleen, and regulating the circulation.  Whenever I find myself growing grim about the mouth; whenever it is a damp, drizzly November in my soul; whenever I find myself involuntarily pausing before coffin warehouses, and bringing up the rear of every funeral I meet; and especially whenever my hypos get such an upper hand of me, that it requires a strong moral principle to prevent me from deliberately stepping into the street, and methodically knocking people's hats off &ndash; then, I account it high time to get to sea as soon as I can.</p>	
	</div>
</div>

the fiddle

(resize browser's window for testing)

Solution 5 - Html

After looking over the W3 spec for text-overflow, I don't think this is possible using only CSS. Ellipsis is a new-ish property, so it probably hasn't received much usage or feedback as of yet.

However, this guy appears to have asked a similar (or identical) question, and someone was able to come up with a nice jQuery solution. You can demo the solution here: http://jsfiddle.net/MPkSF/

If javascript is not an option, I think you may be out of luck...

Solution 6 - Html

Just want to add to this question for completeness sake.

Solution 7 - Html

Great question... I wish there was an answer, but this is the closest you can get with CSS these days. No ellipsis, but still pretty usable.

overflow: hidden;
line-height: 1.2em;
height: 3.6em;      // 3 lines * line-height

Solution 8 - Html

I've found this css (scss) solution that works quite well. On webkit browsers it shows the ellipsis and on other browsers it just truncates the text. Which is fine for my intended use.

$font-size: 26px;
$line-height: 1.4;
$lines-to-show: 3;

h2 {
  display: block; /* Fallback for non-webkit */
  display: -webkit-box;
  max-width: 400px;
  height: $font-size*$line-height*$lines-to-show; /* Fallback for non-webkit */
  margin: 0 auto;
  font-size: $font-size;
  line-height: $line-height;
  -webkit-line-clamp: $lines-to-show;
  -webkit-box-orient: vertical;
  overflow: hidden;
  text-overflow: ellipsis;
}

An example by the creator: http://codepen.io/martinwolf/pen/qlFdp

Solution 9 - Html

There are many answers here but I needed one that was:

  • CSS Only
  • Future-proof (gets more compatible with time)
  • Not going to break words apart (only breaks on spaces)

The caveat is that it doesn't provide an ellipsis for the browsers that don't support the -webkit-line-clamp rule (currently IE, Edge, Firefox) but it does use a gradient to fade their text out.

.clampMe {
  position: relative;
  height: 2.4em; 
  overflow: hidden;
}

.clampMe:after {
  content: "";
  text-align: right;
  position: absolute;
  bottom: 0;
  right: 0;
  width: 50%;
  height: 1.2em; /* Just use multiples of the line-height */
  background: linear-gradient(to right, rgba(255, 255, 255, 0), rgba(255, 255, 255, 1) 80%);
}

/* Now add in code for the browsers that support -webkit-line-clamp and overwrite the non-supportive stuff */
@supports (-webkit-line-clamp: 2) {
  .clampMe {
      overflow: hidden;
      text-overflow: ellipsis;
      display: -webkit-box;
      -webkit-line-clamp: 2;
      -webkit-box-orient: vertical;
  }
  
  .clampMe:after {
    display: none;
  }
}

There's a lot more text in here than what you'll ever see. Pellentesque habitant testalotish morbi tristique senectus et netus et malesuada fames ac turpis egestas. Vestibulum tortor quam, feugiat vitae, ultricies eget, tempor sit amet, ante. Donec eu libero sit amet quam egestas semper. Aenean ultricies mi vitae est. Mauris placerat eleifend leo.

You can see it in action in this CodePen and you can also see a Javascript version here (no jQuery).

Solution 10 - Html

Here is the closest solution I could get using just css.

###HTML

<div class="ellipsis"> <span>...</span>
Hello this is Mr_Green from Stackoverflow. I love CSS. I live in CSS and I will never leave working on CSS even my work is on other technologies.</div>

###CSS

div {
    height: 3em;
    line-height: 1.5em;
    width: 80%;
    border: 1px solid green;
    overflow: hidden;
    position: relative;
}
div:after {
    content:". . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .  . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .  . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .  . . . . . . . . . . . . . . . . . . . . . . . . . . . .";
    background-color: white;
    color: white;
    display: inline;
    position: relative;
    box-shadow: 8px 1px 1px white;
    z-index: 1;
}
span {
    position: absolute;
    bottom: 0px;
    right: 0px;
    background-color: white;
}

##Working Fiddle (resize the window to check)

###Link to my blog for explanation

##Updated Fiddle

I hope now some css expert would have got idea on how to make it perfect. :)

Solution 11 - Html

Bit late to this party but I came up with, what I think, is a unique solution. Rather than trying to insert your own ellipsis through css trickery or js I thought i'd try and roll with the single line only restriction. So I duplicate the text for every "line" and just use a negative text-indent to make sure one line starts where the last one stops. FIDDLE

CSS:

#wrapper{
    font-size: 20pt;
    line-height: 22pt;
    width: 100%;
    overflow: hidden;
    padding: 0;
    margin: 0;
}

.text-block-line{
    height: 22pt;
    display: inline-block;
    max-width: 100%;
    overflow: hidden;
    white-space: nowrap;
    width: auto;
}
.text-block-line:last-child{
    text-overflow: ellipsis;
}

/*the follwing is suboptimal but neccesary I think. I'd probably just make a sass mixin that I can feed a max number of lines to and have them avialable. Number of lines will need to be controlled by server or client template which is no worse than doing a character count clip server side now. */
.line2{
    text-indent: -100%;
}
.line3{
    text-indent: -200%;
}
.line4{
    text-indent: -300%;
}

HTML:

<p id="wrapper" class="redraw">
    <span class="text-block-line line1">This text is repeated for every line that you want to be displayed in your element. This example has a max of 4 lines before the ellipsis occurs. Try scaling the preview window width to see the effect.</span>
    <span class="text-block-line line2">This text is repeated for every line that you want to be displayed in your element. This example has a max of 4 lines before the ellipsis occurs. Try scaling the preview window width to see the effect.</span>
    <span class="text-block-line line3">This text is repeated for every line that you want to be displayed in your element. This example has a max of 4 lines before the ellipsis occurs. Try scaling the preview window width to see the effect.</span>
    <span class="text-block-line line4">This text is repeated for every line that you want to be displayed in your element. This example has a max of 4 lines before the ellipsis occurs. Try scaling the preview window width to see the effect.</span>
</p>

More details in the fiddle. There is an issue with the browser reflowing that I use a JS redraw for and such so do check it out but this is the basic concept. Any thoughts/suggestions are much appreciated.

Solution 12 - Html

thanks @balpha and @Kevin, I combine two method together.

no js needed in this method.

you can use background-image and no gradient needed to hide dots.

the innerHTML of .ellipsis-placeholder is not necessary, I use .ellipsis-placeholder to keep the same width and height with .ellipsis-more. You could use display: inline-block instead.

<div class="ellipsis ellipsis-height ellipsis-line-height">
    <div class="ellipsis-more-top ellipsis-height"></div>
    <div class="ellipsis-text-container">
        <div class="ellipsis-placeholder-top ellipsis-height ellipsis-margin-top"></div>
        <div class="ellipsis-placeholder">
           <span>...</span><span>more</span>
        </div>
        <span class="ellipsis-text">text text text text text text text text text text text text text text text text text text text text text text text text text text text text text text text text text text text text text text text text text text text text text text text text text text text text text text text text text text text </span>
    </div>
    <div class="ellipsis-more-container ellipsis-margin-top">
        <div class="ellipsis-more">
            <span>...</span><span>more</span>
        </div>
    </div>
</div>

.ellipsis {
    overflow: hidden;
    position: relative;
}
.ellipsis-more-top {/*push down .ellipsis-more*/
    content: "";
    float: left;
    width: 5px;
}
.ellipsis-text-container {
    float: right;
    width: 100%;
    margin-left: -5px;
}
.ellipsis-more-container {
    float: right;
    position: relative;
    left: 100%;
    width: 5px;
    margin-left: -5px;
    border-right: solid 5px transparent;
    white-space: nowrap;
}
.ellipsis-placeholder {/*keep text around ,keep it transparent ,keep same width and height as .ellipsis-more*/
    float: right;
    clear: right;
    color: transparent;
}
.ellipsis-placeholder-top {/*push down .ellipsis-placeholder*/
    float: right;
    width: 0;
}
.ellipsis-more {/*ellipsis things here*/
    float: right;
}
.ellipsis-height {/*the total height*/
    height: 3.6em;
}
.ellipsis-line-height {/*the line-height*/
    line-height: 1.2;
}
.ellipsis-margin-top {/*one line height*/
    margin-top: -1.2em;
}
.ellipsis-text {
    word-break: break-all;
}

jsfiddler

Solution 13 - Html

display: -webkit-box;
-webkit-line-clamp: 3;
-webkit-box-orient: vertical; 

see more click here

Solution 14 - Html

javascript solution will be better

  • get the lines number of text
  • toggle is-ellipsis class if the window resize or elment change

getRowRects

Element.getClientRects() works like this

enter image description here

each rects in the same row has the same top value, so find out the rects with different top value, like this

enter image description here

function getRowRects(element) {
    var rects = [],
        clientRects = element.getClientRects(),
        len = clientRects.length,
        clientRect, top, rectsLen, rect, i;

    for(i=0; i<len; i++) {
        has = false;
        rectsLen = rects.length;
        clientRect = clientRects[i];
        top = clientRect.top;
        while(rectsLen--) {
            rect = rects[rectsLen];
            if (rect.top == top) {
                has = true;
                break;
            }
        }
        if(has) {
            rect.right = rect.right > clientRect.right ? rect.right : clientRect.right;
            rect.width = rect.right - rect.left;
        }
        else {
            rects.push({
                top: clientRect.top,
                right: clientRect.right,
                bottom: clientRect.bottom,
                left: clientRect.left,
                width: clientRect.width,
                height: clientRect.height
            });
        }
    }
    return rects;
}

float ...more

like this

enter image description here

detect window resize or element changed

like this

enter image description here

enter image description here

enter image description here

Solution 15 - Html

I found a javascript trick, but you have to use the length of the string. Lets say you want 3 lines of width 250px, you can calculate the length per line i.e.

//get the total character length.
//Haha this might vary if you have a text with lots of "i" vs "w"
var totalLength = (width / yourFontSize) * yourNumberOfLines

//then ellipsify
function shorten(text, totalLength) {
    var ret = text;
    if (ret.length > totalLength) {
        ret = ret.substr(0, totalLength-3) + "...";
    }
    return ret;
}

Solution 16 - Html

a pure css method base on -webkit-line-clamp:

@-webkit-keyframes ellipsis {/*for test*/
    0% { width: 622px }
    50% { width: 311px }
    100% { width: 622px }
}
.ellipsis {
    max-height: 40px;/* h*n */
    overflow: hidden;
    background: #eee;

    -webkit-animation: ellipsis ease 5s infinite;/*for test*/
    /**
    overflow: visible;
    /**/
}
.ellipsis .content {
    position: relative;
    display: -webkit-box;
    -webkit-box-orient: vertical;
    -webkit-box-pack: center;
    font-size: 50px;/* w */
    line-height: 20px;/* line-height h */
    color: transparent;
    -webkit-line-clamp: 2;/* max row number n */
    vertical-align: top;
}
.ellipsis .text {
    display: inline;
    vertical-align: top;
    font-size: 14px;
    color: #000;
}
.ellipsis .overlay {
    position: absolute;
    top: 0;
    left: 50%;
    width: 100%;
    height: 100%;
    overflow: hidden;

    /**
    overflow: visible;
    left: 0;
    background: rgba(0,0,0,.5);
    /**/
}
.ellipsis .overlay:before {
    content: "";
    display: block;
    float: left;
    width: 50%;
    height: 100%;

    /**
    background: lightgreen;
    /**/
}
.ellipsis .placeholder {
    float: left;
    width: 50%;
    height: 40px;/* h*n */

    /**
    background: lightblue;
    /**/
}
.ellipsis .more {
    position: relative;
    top: -20px;/* -h */
    left: -50px;/* -w */
    float: left;
    color: #000;
    width: 50px;/* width of the .more w */
    height: 20px;/* h */
    font-size: 14px;

    /**
    top: 0;
    left: 0;
    background: orange;
    /**/
}

<div class='ellipsis'>
    <div class='content'>
        <div class='text'>text text text text text text text text text text text text text text text text text text text text text </div>
        <div class='overlay'>
            <div class='placeholder'></div>
            <div class='more'>...more</div>
        </div>
    </div>
</div>

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionOviliaView Question on Stackoverflow
Solution 1 - HtmlJim ThomasView Answer on Stackoverflow
Solution 2 - HtmlbalphaView Answer on Stackoverflow
Solution 3 - HtmlDanieldView Answer on Stackoverflow
Solution 4 - HtmlKevinView Answer on Stackoverflow
Solution 5 - HtmlJeffView Answer on Stackoverflow
Solution 6 - HtmlMattView Answer on Stackoverflow
Solution 7 - HtmlAdam FraserView Answer on Stackoverflow
Solution 8 - HtmlNikola LajicView Answer on Stackoverflow
Solution 9 - HtmlNilsyNilsView Answer on Stackoverflow
Solution 10 - HtmlMr_GreenView Answer on Stackoverflow
Solution 11 - HtmlluposView Answer on Stackoverflow
Solution 12 - HtmlDefimsView Answer on Stackoverflow
Solution 13 - HtmlelrrrrrrrView Answer on Stackoverflow
Solution 14 - HtmlDefimsView Answer on Stackoverflow
Solution 15 - HtmlTremmilliciousView Answer on Stackoverflow
Solution 16 - HtmlDefimsView Answer on Stackoverflow