Skip to content Skip to sidebar Skip to footer

How To Check If Text Is Truncated By Css Using Javascript

I am trying to detect if the text is truncated using JS. The solution mentioned here works great except for an edge case below. As you will notice, the first block on mouse hover w

Solution 1:

The problem here is that both HTMLElement.offsetWidth and Element.scrollWidth are rounded values. Your element's true inner-width is actually 300.40625px on my computer, and this gets floored to 300px in my Chrome.

The solution here is to use APIs that return float values, and there aren't much...

One could be tempted to check the inner <a>'s getBoundingClientRect().width, and that would actually work in all OP's cases, but that would only work in these case: Add a padding to the div, a margin to these <a>, or an other element and it's broken.

document.querySelectorAll( ".test" ).forEach( el => {
  el.classList.toggle( "truncated", isEllipsisActive( el ) );
} );

functionisEllipsisActive( el ) {
  return el.firstElementChild.getBoundingClientRect().width > el.getBoundingClientRect().width;
}
div.test {
  margin-bottom: 1em;
  background: red;
  color: #fff;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  width: 300px;
}
div.truncated {
  background: green;
}
.margin-left {
  margin-left: 225px;
}
<!-- should be green --><divclass="test"><a>Analytics reports comes through garbled. Plsss</a></div><!-- should be green --><divclass="test"><a>Analytics reports comes through garbled. Plsssssss</a></div><!-- should be green --><divclass="test"><a>Analytics</a><a> reports comes through garbled. Plsssssss</a></div><!-- should be green --><divclass="test"><aclass="margin-left">Shorter text</a></div><!-- should be red --><divclass="test"><a>Normal text</a></div>

So one might think a Range and its getBoundingClientRect() method would do, however, while this is able to tell the real size of the text content in your element, this only checks for the text content. If the scrolling is caused by a margin, it won't work.

document.querySelectorAll(".test").forEach( el => {
    el.classList.toggle( "truncated", isEllipsisActive( el ) );
} );

functionisEllipsisActive( el ) {
  return el.scrollWidth !== el.offsetWidth ?
    el.scrollWidth > el.offsetWidth :
    checkRanges( el ); // Blink and Webkit browsers do floor scrollWidth
}

functioncheckRanges( el ) {
  const range = newRange();
  range.selectNodeContents( el );
  
  const range_rect = range.getBoundingClientRect();
  const el_rect = el.getBoundingClientRect();
  // assumes ltr directionreturn range_rect.right > el_rect.right;
}
div.test {
  margin-bottom: 1em;
  background: red;
  color: #fff;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  width: 300px;
}
div.truncated {
  background: green;
}
.margin-left {
  margin-left: 225px;
}

.margin-right {
  margin-right: 225px;
}
<!-- should be green --><divclass="test"><a>Analytics reports comes through garbled. Plsss</a></div><!-- should be green --><divclass="test"><a>Analytics reports comes through garbled. Plsssssss</a></div><!-- should be green --><divclass="test"><a>Analytics</a><a> reports comes through garbled. Plsssssss</a></div><!-- should be green --><divclass="test"><aclass="margin-left">Shorter text</a></div><!-- should be green --><divclass="test"><aclass="margin-right">Shorter text</a></div><!-- should be red --><divclass="test"><a>Normal text</a></div>

So the only solution I could think of relies on a Chrome specific behavior: They do expose the Client Rect of the rendered ellipsis in the result of Range.getClientRects(). So a way to know for sure, in Chrome, if the ellipsis is rendered, is to toggle the text-overflow property and check if this DOMRect appeared.

However, since this is a Chrome only behavior, we still need to check for the Range's bounding-box position for Safari.

document.querySelectorAll(".test").forEach( el => {
    el.classList.toggle( "truncated", isEllipsisActive( el ) );
} );

functionisEllipsisActive( el ) {
  return el.scrollWidth !== el.offsetWidth ?
    el.scrollWidth > el.offsetWidth :
    checkRanges( el ); // Blink and Webkit browsers do floor scrollWidth
}

functioncheckRanges( el ) {
  const range = newRange();
  range.selectNodeContents( el );
  
  const range_rect = range.getBoundingClientRect();
  const el_rect = el.getBoundingClientRect();
  // assumes ltr directionif( range_rect.right > el_rect.right ) {
    returntrue;
  }
  // Following check would be enough for Blink browsers// but they are the only ones exposing this behavior.// first force ellipsis
  el.classList.add( "text-overflow-ellipsis" );
  // get all the client rects (there should be one for the ellipsis)const rects_ellipsis = range.getClientRects();
  // force no ellipsis
  el.classList.add( "text-overflow-clip" );
  const rects_clipped = range.getClientRects();
  // clean
  el.classList.remove( "text-overflow-ellipsis" );
  el.classList.remove( "text-overflow-clip" );
  // if the counts changed, the text is truncatedreturn rects_clipped.length !== rects_ellipsis.length;
}
/* 2 new clasess to force the rendering of ellipsis */.text-overflow-ellipsis {
  text-overflow: ellipsis !important;
}
.text-overflow-clip {
  text-overflow: clip !important;
}

div.test {
  margin-bottom: 1em;
  background: red;
  color: #fff;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  width: 300px;
}
div.truncated {
  background: green;
}
.margin-left {
  margin-left: 225px;
}
.margin-right {
  margin-right: 225px;
}
<!-- should be green --><divclass="test"><a>Analytics reports comes through garbled. Plsss</a></div><!-- should be green --><divclass="test"><a>Analytics reports comes through garbled. Plsssssss</a></div><!-- should be green --><divclass="test"><a>Analytics</a><a> reports comes through garbled. Plsssssss</a></div><!-- should be green --><divclass="test"><aclass="margin-left">Shorter text</a></div><!-- should be green --><divclass="test"><aclass="margin-right">Shorter text</a></div><!-- should be red --><divclass="test"><a>Normal text</a></div>

Solution 2:

Try using

functionisEllipsisActive(e) {
  var c = e.cloneNode(true);
  c.style.display = 'inline';
  c.style.width = 'auto';
  c.style.visibility = 'hidden';
  document.body.appendChild(c);
  const truncated = c.offsetWidth >= e.clientWidth;
  c.remove();
  return truncated;
}

It's hacky, but it works.

Post a Comment for "How To Check If Text Is Truncated By Css Using Javascript"