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>