Detecting Text Ellipsis and Showing a Popper on Hover with CSS and JavaScript
This article explains how to apply CSS ellipsis to truncate overflowing text, then use JavaScript—particularly the createRange API and temporary DOM measurements—to detect when truncation occurs and display a popper tooltip only on hover, comparing several practical implementation methods.
To truncate text with an ellipsis after it exceeds its container width, simply add the following CSS class:
.ellipsis {
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}The challenge arises when you want a popper (tooltip) to appear on hover only if the text is actually truncated. Since CSS cannot inform JavaScript about the truncation state, we need JavaScript to calculate it.
Using document.createRange()
Element‑plus’s table component already implements this detection. The relevant source can be found at GitHub . The core idea is to create a Range covering the cell’s content, obtain its getBoundingClientRect() dimensions, and compare them with the cell’s actual width/height (adjusting for padding). If the range size plus padding exceeds the cell size, the text is ellipsed and a popper is created.
// Simplified snippet from Element‑plus
const cellChild = (event.target as HTMLElement).querySelector('.cell');
const range = document.createRange();
range.setStart(cellChild, 0);
range.setEnd(cellChild, cellChild.childNodes.length);
let rangeWidth = range.getBoundingClientRect().width;
let rangeHeight = range.getBoundingClientRect().height;
// Remove tiny decimal parts
if (rangeWidth - Math.floor(rangeWidth) < 0.001) rangeWidth = Math.floor(rangeWidth);
if (rangeHeight - Math.floor(rangeHeight) < 0.001) rangeHeight = Math.floor(rangeHeight);
const { top, left, right, bottom } = getPadding(cellChild);
const horizontalPadding = left + right;
const verticalPadding = top + bottom;
if (rangeWidth + horizontalPadding > cellChild.offsetWidth ||
rangeHeight + verticalPadding > cellChild.offsetHeight ||
cellChild.scrollWidth > cellChild.offsetWidth) {
createTablePopper(parent?.refs.tableWrapper, cell, cell.innerText || cell.textContent, nextZIndex, tooltipOptions);
}The document.createRange() method creates a Range object that can:
Set a selectable text range using setStart() and setEnd() .
Insert new nodes with insertNode() .
Retrieve position and size via getBoundingClientRect() .
Element‑plus also discards fractional parts smaller than 0.001 to avoid precision issues.
Basic Ellipsis Demo
<div class="ellipsis box">
Lorem ipsum dolor sit amet consectetur adipisicing elit.
</div>
<style>
.ellipsis { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.box { border: 1px solid gray; padding: 10px; }
</style>Note the distinction between clientWidth and offsetWidth . Because a 1 px border adds to offsetWidth , we use clientWidth to represent the actual content width.
Measuring Width with a Temporary Element
Another approach creates an off‑screen clone of the target element without overflow:hidden to measure its natural width.
const checkEllipsis = () => {
const range = document.createRange();
range.setStart(box, 0);
range.setEnd(box, box.childNodes.length);
const rangeWidth = range.getBoundingClientRect().width;
const { pLeft, pRight } = getPadding(box);
const horizontalPadding = pLeft + pRight;
if (rangeWidth + horizontalPadding > box.clientWidth) {
result.textContent = '存在省略号';
} else {
result.textContent = '容器宽度足够,没有省略号了';
}
};Block Wrapper Method
By ensuring the outer container is a block element and the inner content is inline, the inner element’s offsetWidth remains unchanged while the outer block can be ellipsed.
<div class="ellipsis box">
<span class="content">
Lorem ipsum dolor sit amet consectetur adipisicing elit. Lorem ipsum dolor sit amet consectetur adipisicing elit.
</span>
</div>
<style>
.ellipsis { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.box { border: 1px solid gray; padding: 10px; }
</style>The detection logic simply compares box.clientWidth with content.offsetWidth + horizontalPadding to decide whether an ellipsis is present.
Method Comparison
Performance (subjective): Method 3 > Method 1 > Method 2.
Ease of use: Method 1 > Method 3 > Method 2.
Precision (subjective): All three are almost equal; if forced, Method 3 > Method 1 > Method 2.
The author plans to explore other component libraries for additional solutions, noting that front‑end work often involves many tiny but important details.
If this article helped you, feel free to follow, like, and bookmark.
Rare Earth Juejin Tech Community
Juejin, a tech community that helps developers grow.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.