15
----------------------------------------------------
| This is my text inside a div and I want the overf|low of the text to be cut
----------------------------------------------------

Please note that I want the overflow to be removed, so the CSS ellipsis property would not work for me. So basically, I want that the text above to appear like this:

----------------------------------------------------
| This is my text inside a div and I want the overf|
----------------------------------------------------

How is this possible with pure JavaScript?

EDIT

I need a JavaScript function to crop the text because I need to count the characters of the visible text.

jamesmortensen
  • 33,636
  • 11
  • 99
  • 120
Savas Vedova
  • 5,622
  • 2
  • 28
  • 44

5 Answers5

6

Okay, I didn't see the addendum to the question. Although I had previously said it wasn't possible to do this using JavaScript and a font that isn't fixed-width... it actually is possible!

You can wrap each individual character in a <span>, and find the first <span> that is outside the bounds of the parent. Something like:

function countVisibleCharacters(element) {
    var text = element.firstChild.nodeValue;
    var r = 0;

    element.removeChild(element.firstChild);

    for(var i = 0; i < text.length; i++) {
        var newNode = document.createElement('span');
        newNode.appendChild(document.createTextNode(text.charAt(i)));
        element.appendChild(newNode);

        if(newNode.offsetLeft < element.offsetWidth) {
            r++;
        }
    }

    return r;
}

Here's a demo.

Ry-
  • 218,210
  • 55
  • 464
  • 476
  • Again, that's not what Im looking for. Thanks anyway. – Savas Vedova May 05 '12 at 18:40
  • but no way to count visible chars – Jirka Kopřiva May 05 '12 at 18:40
  • @SavasVedova: Oh, okay, just noticed your question edit. That's not possible unless you're using a fixed-width font. – Ry- May 05 '12 at 18:40
  • is setting the div `width` ok? if so, just add that to `#myDiv` – tim peterson May 05 '12 at 18:43
  • 1
    @timpeterson: See demo. I don't include application-specific metrics in generic answers as a rule :) – Ry- May 05 '12 at 18:44
  • @SavasVedova: I retract that statement, it is possible! See edit. – Ry- May 05 '12 at 18:53
  • It does not count correctly yet but I get the idea :) Thanks. – Savas Vedova May 05 '12 at 18:57
  • cool nice solution, i actually was looking for a JS solution for this myself, 2 birds, one stone. thanks @minitech! – tim peterson May 05 '12 at 19:12
  • @SavasVedova: Nicely done! (And sorry about the bug. It worked in Firefox, but apparently not much else `:)`) – Ry- May 14 '12 at 00:29
  • I forked this decision to maintain multiline blocks - [jsfiddle.net/maslenkov/pm8nqron](http://jsfiddle.net/maslenkov/pm8nqron/2/). It has diff only in js line 12 and in css. So it possible to replace some ended symbols with link "read more". – Евгений Масленков Feb 13 '15 at 09:55
  • Based on this solution I've made a MULTILINE-ELLIPSIS directive - https://jsfiddle.net/Tomer_Easybizy/kk3p1m21/ – Tomer Feb 08 '16 at 09:50
  • @Ry- On my test (Ubuntu, chrome), your demo function it says there are 72 visible characters while only 14 characters are, which is incorrect. I have been looking for any solution around this for long time and tried different ways to get around this. When I saw your answer gave me a hope. However, until now, I think this is impossible. Thanks for your post anyway – Telvin Nguyen Jan 16 '20 at 08:22
  • @TelvinNguyen: That’s odd – this approach should be pretty reliable. Do you have any extensions enabled? Does logging `newNode.offsetLeft` at each iteration show anything helpful? – Ry- Jan 16 '20 at 13:24
3

You can do this with Javascript. Here is a function that counts the number of visible characters in an element, regardless of external css sheets and inline styles applied to the element. I've only tested it in Chrome, but I think it is cross browser friendly:

function count_visible(el){
    var padding, em, numc;
    var text = el.firstChild.data;
    var max = el.clientWidth;

    var tmp = document.createElement('span');
    var node = document.createTextNode();
    tmp.appendChild(node);
    document.body.appendChild(tmp);

    if(getComputedStyle)
        tmp.style.cssText = getComputedStyle(el, null).cssText;
    else if(el.currentStyle)
        tmp.style.cssText = el.currentStyle.cssText;

    tmp.style.position = 'absolute';
    tmp.style.overflow = 'visible';
    tmp.style.width = 'auto';

    // Estimate number of characters that can fit.
    padding = tmp.style.padding;
    tmp.style.padding = '0';
    tmp.innerHTML = 'M';
    el.parentNode.appendChild(tmp);
    em = tmp.clientWidth;
    tmp.style.padding = padding;      
    numc = Math.floor(max/em);

    var width = tmp.clientWidth;

    // Only one of the following loops will iterate more than one time
    // Depending on if we overestimated or underestimated.

    // Add characters until we reach overflow width
    while(width < max && numc <= text.length){
        node.nodeValue = text.substring(0, ++numc);
        width = tmp.clientWidth;
    }

    // Remove characters until we no longer have overflow
    while(width > max && numc){
        node.nodeValue = text.substring(0, --numc);
        width = tmp.clientWidth;
    }

    // Remove temporary div
    document.body.removeChild(tmp);

    return numc;
}

JSFiddle Example

Paul
  • 139,544
  • 27
  • 275
  • 264
  • To test it try changing the width in the css until the next character is fully visible (should be 304px if JSFiddle's normalize CSS is perfect). – Paul May 05 '12 at 19:34
  • @Delta Can you give an example so I can improve it? – Paul Jul 25 '12 at 00:14
2

try this, it requires a fixed width if that is ok with you: http://jsfiddle.net/timrpeterson/qvZKw/20/

HTML:

<div class="col">This is my text inside a div and I want the overf|low of the text to be cut</div>

CSS:

.col { 
   width:120px; 
    overflow: hidden;
   white-space:nowrap;

 }​
tim peterson
  • 23,653
  • 59
  • 177
  • 299
2

You're trying to force a CSS problem into JavaScript. Put the hammer away and get out a screwdriver. http://en.wiktionary.org/wiki/if_all_you_have_is_a_hammer,_everything_looks_like_a_nail

Solving the answer of character count is probably irrelevant if you take a step back. The last character could be only partially visible, and character count is drastically different given font size changes, the difference of width between W an i, etc. Probably the div's width is more important than the character count in the true problem.

If you're still stuck on figuring out the characters visible, put a span inside the div around the text, use the css provided in other answers to this question, and then in JavaScript trim one character at a time off the string until the span's width is less than the div's width. And then watch as your browser freezes for a few seconds every time you do that to a big paragraph.

robrich
  • 13,017
  • 7
  • 36
  • 63
  • @robic, just fyi, the questioner edited their question, looks like they need a JS solution. – tim peterson May 05 '12 at 19:17
  • @timpeterson: yes, but it's still the wrong tool for the job. – robrich May 05 '12 at 19:20
  • @robich what's the right tool considering they "need to count the characters of the visible text"? I'm being completely honest, maybe I'm confused and don't know what you are referring to. – tim peterson May 05 '12 at 19:35
  • @timpeterson my proposal is that the premise of "need to count characters" is flawed. Probably the true problem is "choose an appropriate div width" or "avoid loading too much data on the page if it won't get shown" or "the css-trim-technique has a visually unappealing right column if my content has long words". If it's merely "trim excessively wide columns", then use CSS. – robrich May 05 '12 at 19:54
  • @robich fair enough, I started to think that the ultimate application for this character count was as a pagination strategy (e.g., slideshow). So going the JS route made sense to me. But yeah, think we've covered it all, thanks for the chat, – tim peterson May 05 '12 at 20:02
  • If it's a very large paragraph you could use a binary search instead of linear to count the number of visible characters. – Paul Apr 03 '13 at 11:02
0

.col { width:40px; overflow: hidden; white-space:nowrap; }

White-space: nowrap; is needed when the content has spaces.

Either way, long words in single lines do not appear. http://jsfiddle.net/h6Bhb/

Tina CG Hoehr
  • 6,721
  • 6
  • 44
  • 57