Below I've written some code that takes some content in a table cell and truncates it to two lines if it runs over. When trying to find the correct content length that is close to 2 full lines (but does not go over!) I take a logarithmic approach (I think). I first cut the content in half. I then check the content again and either add or subtract a quarter (half of the half). Etc.
Requirements:
- Ellipsis (...) at the end of truncated text.
- Responsive, strategy should work for dynamic width cells
Questions:
- In the snippet, I've included an example that results in 3 lines. How can I guarantee I land at 2 lines while getting reasonably close to 2 full lines?
- I did the logarithmic approach so I wouldn't have to do something like pop a word, retest, pop a word, retest, etc. This still seems too expensive, how can I improve this?
document.querySelectorAll('.expand').forEach(td => { // get cell styles let styles = window.getComputedStyle(td); let lineHeight = parseInt(styles.lineHeight, 10); // create test element, mostly because td doesn't support max-height let el = document.createElement('div'); el.innerHTML = td.innerHTML; el.style.maxHeight = (lineHeight * 2) + 'px'; el.style.overflow = 'hidden'; td.appendChild(el); // if scrollHeight is greater than clientHeight, we need to do some expand-y stuff if (el.scrollHeight > el.clientHeight) { // store content let content = el.innerHTML.trim(), len = content.length; for (let i=Math.round(len*.5);; i=Math.round(i*.5)) { let over = el.scrollHeight > el.clientHeight; // if over 2 lines, cut by half // else increase by half over ? (len-=i) : (len+=i); // update innerHTML with updated content el.innerHTML = content.slice(0, len); console.log(i, len); // break if within margin of 10 and we landed under if (i<10 && !over) break; } td.innerHTML = ` <div class="hide-expanded">${el.innerHTML.slice(0, -3).trim()}...</div> <div class="show-expanded">${content}</div> <button type="button">Toggle</button>`; td.querySelector('button').addEventListener('click', e => td.classList.toggle('expanded')) } }); html { font-size: 14px; line-height: 24px; font-family: Helvetica, Arial, sans-serif; } table { border-collapse: collapse; } td { white-space: nowrap; padding: 1rem; } .expand { white-space: normal; } .expand:not(.expanded) .show-expanded, .expand.expanded .hide-expanded { display: none; } <table> <tbody> <tr> <td class="expand">This is some content. This is some content. This is some content. This is some content. This is some content. This is some content. This is some content. This is some content. This is some content. This is some content. This is some content. This is some content. This is some content. This is some content. This is some content. This is some content. This is some content. This is some content. This is some content. This is some content. This is some content. This is some content. This is some content.</td> </tr> </tbody> </table>