HTML text-overflow ellipsis detection
Asked Answered
E

19

281

I have some elements on my page which have the CSS rules white-space, overflow, text-overflow set, so that overflowing text is trimmed and an ellipsis is used.

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

  border: 1px solid black;
  width: 150px;
  margin: 5px;
  padding: 5px;
  font-family: sans-serif;
}
<div>
  <span>Normal text</span>
</div>
<div>
  <span>Long text that will be trimmed text</span>
</div>

Is there any way I can use JavaScript to detect which elements' contents are overflowing?

Exclaim answered 12/10, 2011 at 9:43 Comment(1)
the ellipsis aspect is irrelevant; all you need to detect is whether it's overflowed.Balcony
T
138

Once upon a time I needed to do this, and the only cross-browser reliable solution I came across was hack job. I'm not the biggest fan of solutions like this, but it certainly produces the correct result time and time again.

The idea is that you clone the element, remove any bounding width, and test if the cloned element is wider than the original. If so, you know it's going to have been truncated.

For example, using jQuery:

var $element = $('#element-to-test');
var $c = $element
           .clone()
           .css({display: 'inline', width: 'auto', visibility: 'hidden'})
           .appendTo('body');

if( $c.width() > $element.width() ) {
    // text was truncated. 
    // do what you need to do
}

$c.remove();

I made a jsFiddle to demonstrate this, http://jsfiddle.net/cgzW8/2/

You could even create your own custom pseudo-selector for jQuery:

$.expr[':'].truncated = function(obj) {
  var $this = $(obj);
  var $c = $this
             .clone()
             .css({display: 'inline', width: 'auto', visibility: 'hidden'})
             .appendTo('body');

  var c_width = $c.width();
  $c.remove();

  if ( c_width > $this.width() )
    return true;
  else
    return false;
};

Then use it to find elements

$truncated_elements = $('.my-selector:truncated');

Demo: http://jsfiddle.net/cgzW8/293/

Hopefully this helps, hacky as it is.

Treat answered 12/10, 2011 at 11:8 Comment(25)
thanks christian, i have seen this before and it looks like this is the only option available to me.Exclaim
Could this work with cloning the text, and seeing if texts match or not?Autolysin
@Autolysin No; CSS truncation doesn't change the actual text in the box, so the content is always the same, whether it's truncated, visible, or hidden. There is still no way to programatically get the truncated text, if there was then you wouldn't need to clone the element in the first place!Treat
Seems that this won't work in situations where there is no white-space: nowrap.Doralia
@JakubHampl What do you mean? The demo I provided right there in my answer has white-space: nowrap and it works... jsfiddle.net/cgzW8/2Treat
@JakubHampl I just deleted white-space: nowrap, and it works in my demo. jsfiddle.net/cgzW8/291. Tested in Chrome, Firefox, Safari, IE8, and IE11.Treat
@JakubHampl Ok I see what you mean. Your wording confused me; it's not that it doesn't work, because it still works. It also works where it shouldn't, and that's the real problem. I'm not a mind reader, so when you tell someone their code "doesn't work", please explain why. It helps everyone involved. However, I've tried to come up with a solution to no avail, what you want to do seems quite difficult.Treat
I must say that after searching a LOT on the internet and tried to implement many solutions, this by far the most reliable one that I found. This solution does not give different results between browsers like element.innerWidth or element.OffsetWidth does which have problem when using margins or padding.. Great solution, Well done.Syd
I agree with Scription, this is the best solution I've found on the net regardless of hackiness. I did however find a problem: If the element in question is quite small, and if it resizes with the page, then it is possible for the difference between the cloned element's width and the original element's width to be less than a pixel. This means the ellipsis can appear even if your code says there is no difference in width. To fix this I used the answer from the following link for more accuracy: #11908014Alisha
Just a note on my last comment: Comparing floating point widths resulted in the opposite problem, so I had to add a tolerance – i.e. if the difference between the cloned element's floating point width and the original's floating point width is less than 0.01 I consider them equal. I realise this makes this for an even more hacky solution but I don't see any other option if you need a more accurate width comparison.Alisha
@AdamGoodwin Thanks for the tip. Subpixels are the bane of my existence. Can you create a jsFiddle with your updated code? I'll then take a look and merge it into my answer.Treat
Here's your original jsFiddle modified with the change: jsfiddle.net/cgzW8/418 The easiest way to see the difference is if you change the css to have a 171.5px width. In Chrome/Firefox/IE this causes an ellipsis to appear, but with the original JavaScript it is not recognised as being truncated, as the width is rounded to 172px.Alisha
The getBoundingClientRect includes borders, so with the change I made it's actually giving 173.5 as the width. But the cloned object is being measured in the same way so it should be ok. There's more info on the function here: developer.mozilla.org/en-US/docs/Web/API/Element/…Alisha
Of the so many QA of elipsis detection, only this answer worked for me. The problem was boundry cases where elipsis was showing but still scrollWidth was less than offsetWidth, This one solved that. Made a small modification for my case though, instead of appending to body appended to current element(td in my case) and immediately removed it. Thanks a lot!!Showily
Great solution, just for me, 'inline-block' works instead of 'inline'Shambles
For me, this did not work anywhere. I'm not sure, how it depends on CSS (i've tried to use it on input controls, the solutions below worked at least in Chrome and Firefox (but not in IE11))...Eolanda
Great solution, especially using jQuery pseudo-selector. But sometimes may not work, because width is calculated incorrectly if the element text has different style (font-size, letter-spacing, margins of inner elements). In that case i would recommend to append clone element to $this.parent() instead of 'body'. This will give exact copy of the element and calculations will be correct. Thanks anywayAlcestis
This doesn't work for me in Firefox. When applying .width() on the truncated element I get 611px, but when getting the width of the newly added element I get 379px. And of course, the reason for this is that my original div had some CSS applied to it that doesn't apply anymore for the cloned div once taken out of its context.Trek
This isnt working for me. Im not using span, Im using input fields. Anyone know if there are any changes required to make this work for inputs?Canto
instead of appending it to body, maybe it's better to append it to element.parentNode? (some css nesting rules that affect width may not apply when you append it to body)Antebi
Here is a vanilla JS version: jsfiddle.net/Ld2pjabu/5 Gist: gist.github.com/guacamoli/859d7853c137b905dc4dc950186d3a22Samella
This is a good solution but as @Antebi mentioned, appending to $element.parent() will keep CSS rules intact that may otherwise make the clone wider than the original. Additionally, you may want to copy the class attribute from the element to the clone to avoid discrepancies caused by CSS. For example, the font size and font family applied by a class may make the clone wider than the original element.Chestonchest
Hello @Treat Verga , i have applied same solution in the same problem but it won't work in a case of both width are same. It won't detect exactly. Please help me out if possible.Escalator
This works but you need to take into account width of the ellipsis you can create span with &hellip; get the width of add to $c.width() or subtract from $element.width()Moses
The problem with appending it to the parentNode is, that in cases where whitespace is set to 'nowrap' or other restricting circumstances, the clone will wind up with the exact width of the element you're trying to check. The idea here is (I think) to append it in a place where the restrictions that caused the ellipsis to kick in do not apply.Acetylide
K
442

Try this JS function, passing the span element as argument:

function isEllipsisActive(e) {
     return (e.offsetWidth < e.scrollWidth);
}
Kirwan answered 4/4, 2012 at 18:42 Comment(15)
This answer and Alex's answer will not work in IE8; there are some odd cases where the scroll width and outerwidth are the same...but it has ellipsis, and then some cases where they are the same...and there is NO ellipsis. In other words, the first solution is the only one that works across all browsers.Teraterai
This does not work for me. I get 0 all the time for every element, for both offsetWidth and scrollWidth, even though I can clearly see the ellipsis. (And I'm not using IE: I'm using the latest version of Chrome.) jsfiddle.net/brandonzylstra/hjk9mvcyHewe
For those who need to understand offsetWidth, scrollWidth, and clientWidth, here is a very good explanation: https://mcmap.net/q/37884/-understanding-offsetwidth-clientwidth-scrollwidth-and-height-respectivelyDickinson
On text-overflow:ellipsis it should be e.offsetWidth <= e.scrollWidthThoer
I'm investigating an issue where the detection seems to be off by one character. I'm detecting overflow one character later than I should. I think there's a slight discrepancy where the ellipsis is shown when the text could actually otherwise fit. I tried temporarily disabling "text-overflow: ellipsis" and sure enough the text fit without any overflow. It might be a browser issue. I'm using Firefox 62 on WIndows 10.Potvaliant
I also tested with clientWidth instead of offsetWidth and the same issue was evident.Potvaliant
They're always equal to each other on flex children, and thus, won't work for them.Warrantee
clean solution but as @Teraterai said it does not always work. Using Mac & Google Chrome there are cases in which offsetWidth equals scrollWidth, wrongly detecting a text-overflow. The 1st answer, although not as nice/simple, seems to work better.Progenitor
Thanks this works on Chrome and FF ok in 2021.Pam
In my case offsetWidth and scrollWidth are always equal. Use offsetHeight and scrollHeight instead to detect overflow. See #52232526Olomouc
My offsetWidth is always 0 during elipsis. what is going one?Ruminant
@NicolasS.Xu I believe if the element is a span, you might get zeros in these properties. So one solution is to wrap the span in a div which has overflow: hidden and then check div properties instead.Unfix
@KenLyon you can get more precise values by using getBoundingClientRect.width. Check out this solution: https://mcmap.net/q/37886/-react-show-material-ui-tooltip-only-for-text-that-has-ellipsisBern
@LeandroOrtiz Perfect, thanks! That's exactly the scenario I observed. Now I just need remember what I needed this for 5 years ago. :)Potvaliant
clientWidth / clientHeight is better. offset will work with normal overflow but will not with line-clamp option.Prevalent
T
138

Once upon a time I needed to do this, and the only cross-browser reliable solution I came across was hack job. I'm not the biggest fan of solutions like this, but it certainly produces the correct result time and time again.

The idea is that you clone the element, remove any bounding width, and test if the cloned element is wider than the original. If so, you know it's going to have been truncated.

For example, using jQuery:

var $element = $('#element-to-test');
var $c = $element
           .clone()
           .css({display: 'inline', width: 'auto', visibility: 'hidden'})
           .appendTo('body');

if( $c.width() > $element.width() ) {
    // text was truncated. 
    // do what you need to do
}

$c.remove();

I made a jsFiddle to demonstrate this, http://jsfiddle.net/cgzW8/2/

You could even create your own custom pseudo-selector for jQuery:

$.expr[':'].truncated = function(obj) {
  var $this = $(obj);
  var $c = $this
             .clone()
             .css({display: 'inline', width: 'auto', visibility: 'hidden'})
             .appendTo('body');

  var c_width = $c.width();
  $c.remove();

  if ( c_width > $this.width() )
    return true;
  else
    return false;
};

Then use it to find elements

$truncated_elements = $('.my-selector:truncated');

Demo: http://jsfiddle.net/cgzW8/293/

Hopefully this helps, hacky as it is.

Treat answered 12/10, 2011 at 11:8 Comment(25)
thanks christian, i have seen this before and it looks like this is the only option available to me.Exclaim
Could this work with cloning the text, and seeing if texts match or not?Autolysin
@Autolysin No; CSS truncation doesn't change the actual text in the box, so the content is always the same, whether it's truncated, visible, or hidden. There is still no way to programatically get the truncated text, if there was then you wouldn't need to clone the element in the first place!Treat
Seems that this won't work in situations where there is no white-space: nowrap.Doralia
@JakubHampl What do you mean? The demo I provided right there in my answer has white-space: nowrap and it works... jsfiddle.net/cgzW8/2Treat
@JakubHampl I just deleted white-space: nowrap, and it works in my demo. jsfiddle.net/cgzW8/291. Tested in Chrome, Firefox, Safari, IE8, and IE11.Treat
@JakubHampl Ok I see what you mean. Your wording confused me; it's not that it doesn't work, because it still works. It also works where it shouldn't, and that's the real problem. I'm not a mind reader, so when you tell someone their code "doesn't work", please explain why. It helps everyone involved. However, I've tried to come up with a solution to no avail, what you want to do seems quite difficult.Treat
I must say that after searching a LOT on the internet and tried to implement many solutions, this by far the most reliable one that I found. This solution does not give different results between browsers like element.innerWidth or element.OffsetWidth does which have problem when using margins or padding.. Great solution, Well done.Syd
I agree with Scription, this is the best solution I've found on the net regardless of hackiness. I did however find a problem: If the element in question is quite small, and if it resizes with the page, then it is possible for the difference between the cloned element's width and the original element's width to be less than a pixel. This means the ellipsis can appear even if your code says there is no difference in width. To fix this I used the answer from the following link for more accuracy: #11908014Alisha
Just a note on my last comment: Comparing floating point widths resulted in the opposite problem, so I had to add a tolerance – i.e. if the difference between the cloned element's floating point width and the original's floating point width is less than 0.01 I consider them equal. I realise this makes this for an even more hacky solution but I don't see any other option if you need a more accurate width comparison.Alisha
@AdamGoodwin Thanks for the tip. Subpixels are the bane of my existence. Can you create a jsFiddle with your updated code? I'll then take a look and merge it into my answer.Treat
Here's your original jsFiddle modified with the change: jsfiddle.net/cgzW8/418 The easiest way to see the difference is if you change the css to have a 171.5px width. In Chrome/Firefox/IE this causes an ellipsis to appear, but with the original JavaScript it is not recognised as being truncated, as the width is rounded to 172px.Alisha
The getBoundingClientRect includes borders, so with the change I made it's actually giving 173.5 as the width. But the cloned object is being measured in the same way so it should be ok. There's more info on the function here: developer.mozilla.org/en-US/docs/Web/API/Element/…Alisha
Of the so many QA of elipsis detection, only this answer worked for me. The problem was boundry cases where elipsis was showing but still scrollWidth was less than offsetWidth, This one solved that. Made a small modification for my case though, instead of appending to body appended to current element(td in my case) and immediately removed it. Thanks a lot!!Showily
Great solution, just for me, 'inline-block' works instead of 'inline'Shambles
For me, this did not work anywhere. I'm not sure, how it depends on CSS (i've tried to use it on input controls, the solutions below worked at least in Chrome and Firefox (but not in IE11))...Eolanda
Great solution, especially using jQuery pseudo-selector. But sometimes may not work, because width is calculated incorrectly if the element text has different style (font-size, letter-spacing, margins of inner elements). In that case i would recommend to append clone element to $this.parent() instead of 'body'. This will give exact copy of the element and calculations will be correct. Thanks anywayAlcestis
This doesn't work for me in Firefox. When applying .width() on the truncated element I get 611px, but when getting the width of the newly added element I get 379px. And of course, the reason for this is that my original div had some CSS applied to it that doesn't apply anymore for the cloned div once taken out of its context.Trek
This isnt working for me. Im not using span, Im using input fields. Anyone know if there are any changes required to make this work for inputs?Canto
instead of appending it to body, maybe it's better to append it to element.parentNode? (some css nesting rules that affect width may not apply when you append it to body)Antebi
Here is a vanilla JS version: jsfiddle.net/Ld2pjabu/5 Gist: gist.github.com/guacamoli/859d7853c137b905dc4dc950186d3a22Samella
This is a good solution but as @Antebi mentioned, appending to $element.parent() will keep CSS rules intact that may otherwise make the clone wider than the original. Additionally, you may want to copy the class attribute from the element to the clone to avoid discrepancies caused by CSS. For example, the font size and font family applied by a class may make the clone wider than the original element.Chestonchest
Hello @Treat Verga , i have applied same solution in the same problem but it won't work in a case of both width are same. It won't detect exactly. Please help me out if possible.Escalator
This works but you need to take into account width of the ellipsis you can create span with &hellip; get the width of add to $c.width() or subtract from $element.width()Moses
The problem with appending it to the parentNode is, that in cases where whitespace is set to 'nowrap' or other restricting circumstances, the clone will wind up with the exact width of the element you're trying to check. The idea here is (I think) to append it in a place where the restrictions that caused the ellipsis to kick in do not apply.Acetylide
E
17

Adding to italo's answer, you can also do this using jQuery.

function isEllipsisActive($jQueryObject) {
    return ($jQueryObject.width() < $jQueryObject[0].scrollWidth);
}

Also, as Smoky pointed out, you may want to use jQuery outerWidth() instead of width().

function isEllipsisActive($jQueryObject) {
    return ($jQueryObject.outerWidth() < $jQueryObject[0].scrollWidth);
}
Economist answered 10/10, 2013 at 19:6 Comment(0)
R
11

Answer from italo is very good! However let me refine it a little:

function isEllipsisActive(e) {
   var tolerance = 2; // In px. Depends on the font you are using
   return e.offsetWidth + tolerance < e.scrollWidth;
}

Cross browser compatibility

If, in fact, you try the above code and use console.log to print out the values of e.offsetWidth and e.scrollWidth, you will notice, on IE, that, even when you have no text truncation, a value difference of 1px or 2px is experienced.

So, depending on the font size you use, allow a certain tolerance!

Rodas answered 2/2, 2016 at 15:53 Comment(2)
It doesn't work on IE10 - offsetWidth is identical to scrollWidth, both giving me the truncated width.Trek
I need this tolerance on Chrome 60 (latest) too.Abracadabra
C
7

This sample show tooltip on cell table with text truncated. Is dynamic based on table width:

$.expr[':'].truncated = function (obj) {
    var element = $(obj);

    return (element[0].scrollHeight > (element.innerHeight() + 1)) || (element[0].scrollWidth > (element.innerWidth() + 1));
};

$(document).ready(function () {
    $("td").mouseenter(function () {
        var cella = $(this);
        var isTruncated = cella.filter(":truncated").length > 0;
        if (isTruncated) 
            cella.attr("title", cella.text());
        else 
            cella.attr("title", null);
    });
});

Demo: https://jsfiddle.net/t4qs3tqs/

It works on all version of jQuery

Challah answered 7/8, 2015 at 7:41 Comment(1)
That's perfect! Exactly what I needed. Just couple of updates from 2023: it should be not $.expr[':'].truncated but $.expr.pseudos.truncated (as of jQuery 3.0), $(...).on('mouseenter', ...) and small improvement for single line $this.attr('title', isTruncated ? $this.text() : null);Moratorium
A
6

All the solutions did not really work for me, what did work was compare the elements scrollWidth to the scrollWidth of its parent (or child, depending on which element has the trigger).

When the child's scrollWidth is higher than its parents, it means .text-ellipsis is active.


When el is the parent element

function isEllipsisActive(el) {
    let width       = el.offsetWidth;
    let widthChild  = el.firstChild.offsetWidth;
    return (widthChild >= width);
}

When el is the child element

function isEllipsisActive(event) {
    let width       = el.offsetWidth;
    let widthParent = el.parentElement.scrollWidth;
    return (width >= widthParent);
}
Austine answered 20/10, 2017 at 13:43 Comment(0)
A
5

elem.offsetWdith VS ele.scrollWidth This work for me! https://jsfiddle.net/gustavojuan/210to9p1/

$(function() {
  $('.endtext').each(function(index, elem) {
    debugger;
    if(elem.offsetWidth !== elem.scrollWidth){
      $(this).css({color: '#FF0000'})
    }
  });
});
Arola answered 8/2, 2016 at 16:59 Comment(1)
Neither works in current Chrome nor Firefox. Both elements become red.Vortical
C
4

My implementation)

const items = Array.from(document.querySelectorAll('.item'));
items.forEach(item =>{
    item.style.color = checkEllipsis(item) ? 'red': 'black'
})

function checkEllipsis(el){
  const styles = getComputedStyle(el);
  const widthEl = parseFloat(styles.width);
  const ctx = document.createElement('canvas').getContext('2d');
  ctx.font = `${styles.fontSize} ${styles.fontFamily}`;
  const text = ctx.measureText(el.innerText);
  return text.width > widthEl;
}
.item{
  width: 60px;
  overflow: hidden;
  text-overflow: ellipsis;
}
      <div class="item">Short</div>
      <div class="item">Loooooooooooong</div>
Cropland answered 5/2, 2020 at 10:0 Comment(0)
B
2

Adding to @Дмытрык answer, missing deduction of borders and paddings to be fully functional!!

const items = Array.from(document.querySelectorAll('.item'));
items.forEach(item =>{
    item.style.color = checkEllipsis(item) ? 'red': 'black'
})

function checkEllipsis(el){
  const styles = getComputedStyle(el);
  const widthEl = parseFloat(styles.width);
  const ctx = document.createElement('canvas').getContext('2d');
  ctx.font = `${styles.fontSize} ${styles.fontFamily}`;
  const text = ctx.measureText(el.innerText);

  let extra = 0;
  extra += parseFloat(styles.getPropertyValue('border-left-width'));
  extra += parseFloat(styles.getPropertyValue('border-right-width'));
  extra += parseFloat(styles.getPropertyValue('padding-left'));
  extra += parseFloat(styles.getPropertyValue('padding-right'));
  return text.width > (widthEl - extra);
}
.item{
  width: 60px;
  overflow: hidden;
  text-overflow: ellipsis;
}
      <div class="item">Short</div>
      <div class="item">Loooooooooooong</div>
Brutus answered 6/4, 2022 at 9:45 Comment(0)
S
1

I think the better way to detect it is use getClientRects(), it seems each rect has the same height, so we can caculate lines number with the number of different top value.

getClientRects work like this

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

getRowRects work like this

you can detect like this

Semipostal answered 7/3, 2016 at 9:35 Comment(0)
B
1

If you're doing react, here's how I did it.

<div 
  ref={ref => {
    if (!ref) return
    const isOverflowing = ref.scrollWidth > ref.clientWidth
    if (isOverflowing) {
      // handle what to do next here
    }
  }}
/>
Boob answered 15/11, 2021 at 2:19 Comment(0)
S
1

There's a small pixel problem with the answers above when comparing offsetWidth > scrollWidth.

W3C has a legacy API that returns element.scrollWidth value as rounded which is causing the comparison in some cases to to return false. If the element width are 150px and the scrollWidth are 150.4px (rounded to 150), then this check will be returning false even if the browser are showing ellipsis in the text.

They have tried to update the APIs that return fractional pixels, but it was reverted due to webcompat.

There's a workaround using max-content and getClientRects(). Here's a sample code that I use onMouseEnter. Note that this only works if the container has a boundary to 100% of the available width (so if you are using flexbox, your container has to be flex: 1 for example.

hasEllipsis(elementItem) {
    let scrollWidth = elementItem.scrollWidth;
    
    elementItem.style.width = 'max-content';
    const itemRects = elementItem.getClientRects();

    if (itemRects.length > 0 && itemRects[0].width > scrollWidth) {
        scrollWidth = itemRects[0].width;
    }

    elementItem.style.width = 'auto';
    return scrollWidth > elementItem.clientWidth;
}

Articles:

https://bugs.chromium.org/p/chromium/issues/detail?id=980476

https://github.com/w3c/csswg-drafts/issues/4123

Struble answered 11/1, 2023 at 12:20 Comment(0)
K
1

By comparing the clientHeight to the scrollHeight it can be inferred that a truncation is happening if the scrollHeight is greater:

enter image description here

Resizable Example:

const isTextTruncated = node => node.scrollHeight > node.clientHeight
const setTextTruncatedClass = node => node.classList.toggle('truncated', isTextTruncated(node))

// Resize DOM observer
const resizeObserver = new ResizeObserver(m => setTextTruncatedClass(m[0].target))
resizeObserver.observe(document.querySelector('p'), { attributes: true })
p {
  display: -webkit-box;
  -webkit-line-clamp: 4;
  -webkit-box-orient: vertical;
  
  width: 300px;
  resize: horizontal;
  overflow: hidden;
}

/* detection label 
 ********************/
body:has(.truncated)::after {
  content: 'Truncated';
  font: 24px Arial;
  background: red;
  color: white;
  padding: 8px;
  position: absolute;
  bottom: 1em;
  right: 1em;
}
<p>
  <b>Resize this text block:</b> Lorem ipsum dolor sit amet, consectetur adipiscing elit, 
  sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. 
  Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris 
  nisi ut aliquip ex ea commodo consequat.
</p>

👉 See my Codepen with a more configurable example

Kathikathiawar answered 19/9, 2023 at 11:57 Comment(0)
G
0

None of the solutions worked for me, so I chose a totally different approach. Instead of using the CSS solution with ellipsis, I just cut the text from a specific string length.

  if (!this.isFullTextShown && this.text.length > 350) {
    return this.text.substring(0, 350) + '...'
  }
  return this.text

and show "more/less" buttons if the length is exceeded.

  <span
    v-if="text.length > 350"
    @click="isFullTextShown = !isFullTextShown"
  >
    {{ isFullTextShown ? 'show less' : 'show more' }}
  </span>
General answered 30/7, 2021 at 16:51 Comment(1)
Loving the fact after 10 years this questions still gets action - although I suspect after 10 years browser standards have improved somewhat! :-)Exclaim
H
0

For someone who uses e.offsetWidth < e.scrollWidth and got a bug that can show full text but still got ellipsis.

It because offsetWidth and scrollWidth always round the value. For example: offsetWidth return 161 but the actual width is 161.25. The solution is use getBoundingClientRect

const clonedEl = e.cloneNode(true)
clonedElement.style.overflow = "visible"
clonedElement.style.visibility = "hidden"
clonedElement.style.width = "fit-content"

e.parentElement.appendChild(clonedEl)
const fullWidth = clonedElement.getBoundingClientRect().width
const currentWidth = e.getBoundingClientRect().width

return currentWidth < fullWidth

Hinda answered 1/6, 2022 at 9:46 Comment(0)
S
0

Case you are using line-clamp >= 2 line for adding ellipsis at more than one line you can use this conditioning:

if (
      descriptionElement &&
      descriptionElement.offsetHeight < descriptionElement.scrollHeight
    ) {
      // has text-overflow
    }
Slating answered 28/7, 2022 at 12:49 Comment(0)
T
-1

The e.offsetWidth < e.scrollWidth solution is not always working.

And if you want to use pure JavaScript, I recommend to use this:

(typescript)

public isEllipsisActive(element: HTMLElement): boolean {
    element.style.overflow = 'initial';
    const noEllipsisWidth = element.offsetWidth;
    element.style.overflow = 'hidden';
    const ellipsisWidth = element.offsetWidth;

    if (ellipsisWidth < noEllipsisWidth) {
      return true;
    } else {
      return false;
    }
}
Tennyson answered 1/8, 2019 at 12:15 Comment(2)
Needing to cause a reflow for each element could potentially be pretty inefficient, like if you're using this across hundreds of cells in a table.Shuping
@Shuping Moreover, a query function that returns the current state of an element should never be allowed to change any property of that element, especially the property queried.Roanne
C
-1

The solution @ItaloBorssatto is perfect. But before looking at SO - I made my decision. Here it is :)

const elems = document.querySelectorAll('span');
elems.forEach(elem => {
  checkEllipsis(elem);
});

function checkEllipsis(elem){
  const canvas = document.createElement('canvas');
  const ctx = canvas.getContext('2d');
  const styles = getComputedStyle(elem);
  ctx.font = `${styles.fontWeight} ${styles.fontSize} ${styles.fontFamily}`;
  const widthTxt = ctx.measureText(elem.innerText).width;
  if (widthTxt > parseFloat(styles.width)){
    elem.style.color = 'red'
  }
}
span.cat {
    display: block;
    border: 1px solid black;
    white-space: nowrap;
    width: 100px;
    overflow: hidden;
    text-overflow: ellipsis;
}
 <span class="cat">Small Cat</span>
      <span class="cat">Looooooooooooooong Cat</span>
Cropland answered 17/1, 2020 at 17:32 Comment(0)
S
-1

there are some mistasks in demo http://jsfiddle.net/brandonzylstra/hjk9mvcy/ mentioned by https://stackoverflow.com/users/241142/iconoclast.

in his demo, add these code will works:

setTimeout(() => {      
  console.log(EntryElm[0].offsetWidth)
}, 0)
Seamus answered 9/4, 2020 at 5:42 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.