Reputation: 403
So ive seen some solutions on stackoverflow how to do this, but the solutions are for a static amount of characters, for example
if (string.length > 20) {
var shortstring= name.substring(0, 20) + " ...";
}
But this is for only 20 characters, I'd like to be able to do it if an element is overflowing out of a container, then replace those characters with three dots.
For example,
asadasddadasadsssssssssssssssssssssssssssssssssssdddddddddddddddddddddddd
Upvotes: 2
Views: 1748
Reputation: 18639
As it is already mentioned in the comments, it's a much easier task to do in CSS.
It has a text-overflow
property, that's invented just for that. When it is set to ellipsis
, it displays a …
character at the end of the visible area.
The spec also allows specifying a custom overflow string (e.g. ' ...'
), however, this is only supported by Firefox.
It can be used like this:
.overflow{
border: 1px solid black;
width: 300px;
overflow: hidden;
white-space: nowrap;
text-overflow: ellipsis;
}
<div class="overflow" >Lorem ipsum dolor sit amet, consectetur adipiscing elit. Pellentesque at enim eget purus tincidunt tincidunt non at orci. Pellentesque urna.</div>
Upvotes: 0
Reputation: 9167
The only way to determine whether a piece of text will overflow a layout container is to actually render the text in that container and then measure its geometry. (This is not true when drawing text in <canvas>
, but I believe that's because canvas text does not care about cascading styles.)
The reason you see so many solutions driven by character-count is because it's simpler, much less computationally expensive (and thus faster), and because the dimensions of any text element are very obviously a function of the amount of text, (among other things -- and there's the rub), so people generally treat it as a quick-and-dirty proxy for actual render dimensions. There's a saying: "sometimes a little inaccuracy can save a ton of explanation." That's what's going on here.
But this is StackOverflow, so let's splurge on explanation. Buckle up. If you want to do this right, here is how you would do it:
This requires a deep knowledge of the styling context on your web page; maybe in your page <span>
within .Column2
is styled such that it will auto-fit to its content, but on my website every element within the target zone receives 2px padding because that's what my layout requires. These details impact the render size.
Do this before you add the element to the target container, or you could get flicker.
element.getBoundingClientRect
.If the text element's width or height are bigger than the container, you've got overflow.
This can repeat many, many times, and DOM manipulation is one of the most-expensive things a browser can do (relatively speaking). This means it's not wise to simply remove one character at a time -- if the text is very much longer than the space allows, your loop could repeat thousands of times, which users will notice, especially if you apply this to more than one chunk of text on the page; if triggered at page load, this would be happening simultaneously to many elements, aka DOM thrashing: RIP your webpage.
That means you need a more-efficient search algorithm. I think the one that's best for this is binary search.
opacity:0
so the text becomes visible. Now you are done.You can probably add a few clever optimizations to that algorithm. For example, to protect against huge chunks of text being crammed into tiny containers, you could create an empty 1em
square element and use that to come up with an upper-bound for the number of characters that will fit. So that 10k sample might get cut down to just 175 as the first step, and then use the guess-and-test process to get from there to whatever is the final value. You could put this special short-circuiting logic inside a guard that only executes if the text is very long.
Or you might cache the final character counts in the browser's localStorage such that refreshing the page with the same content could just read the already-determined counts and render the right amount of text in one step. I suspect the major challenge there would be devising an organizing scheme for the cache data, because the "coordinates" of a cache entry need to include the full starting text and the target container, and you'd want to invalidate the cache if the text or page styling changes.
Many years ago, I used a library called three-dots.js to handle this. I always thought it used binary search, but skimming the source now, that doesn't seem to be the case. Still, it illustrates how complex this is. That is why most people go with character counts: a proper solution is surprisingly complex and much less performant.
You may be able to find a good library on NPM, or use three-dots.js. You can write your own, but unless you have an unlimited amount of time for this, you'd do well to ask yourself if it's really that important to get this exactly perfectly right in every single case. It's a lot easier, and probably fine, to just chop the text conservatively based on character count and manual measurements you take using DevTools.
Upvotes: 1