Insert ellipsis (...) into HTML tag if content too wide
Asked Answered
U

24

151

I have a webpage with an elastic layout that changes its width if the browser window is resized.

In this layout there are headlines (h2) that will have a variable length (actually being headlines from blogposts that I don't have control over). Currently - if they are wider than the window - they are broken into two lines.

Is there an elegant, tested (cross-browser) solution - for example with jQuery - that shortens the innerHTML of that headline tag and adds "..." if the text would be too wide to fit into one line at the current screen/container width?

Unguarded answered 11/2, 2009 at 13:43 Comment(1)
I've created plugin based on this thread that uses CSS properties white-space and word-wrap to format the text. github.com/nothrem/jQuerySmartEllipsisPuglia
B
120

I've got a solution working in FF3, Safari and IE6+ with single and multiline text

.ellipsis {
    white-space: nowrap;
    overflow: hidden;
}

.ellipsis.multiline {
    white-space: normal;
}

<div class="ellipsis" style="width: 100px; border: 1px solid black;">Lorem ipsum dolor sit amet, consectetur adipisicing elit</div>
<div class="ellipsis multiline" style="width: 100px; height: 40px; border: 1px solid black; margin-bottom: 100px">Lorem ipsum dolor sit amet, consectetur adipisicing elit</div>

<script type="text/javascript" src="/js/jquery.ellipsis.js"></script>
<script type="text/javascript">
$(".ellipsis").ellipsis();
</script>

jquery.ellipsis.js

(function($) {
    $.fn.ellipsis = function()
    {
        return this.each(function()
        {
            var el = $(this);

            if(el.css("overflow") == "hidden")
            {
                var text = el.html();
                var multiline = el.hasClass('multiline');
                var t = $(this.cloneNode(true))
                    .hide()
                    .css('position', 'absolute')
                    .css('overflow', 'visible')
                    .width(multiline ? el.width() : 'auto')
                    .height(multiline ? 'auto' : el.height())
                    ;

                el.after(t);

                function height() { return t.height() > el.height(); };
                function width() { return t.width() > el.width(); };

                var func = multiline ? height : width;

                while (text.length > 0 && func())
                {
                    text = text.substr(0, text.length - 1);
                    t.html(text + "...");
                }

                el.html(t.html());
                t.remove();
            }
        });
    };
})(jQuery);
Bond answered 20/6, 2009 at 22:9 Comment(16)
Nice, I've been looking how to handle overflow with multiple lines. One improvement: instead of appending three periods, append the ellipsis character, '…'.Pleasance
This works very well. You should publish this on the jQuery site.Signor
Although in IE if ellipsis function is applied on a div that just has a link, after ellipsis the link disappears. Any pointers on this?Grizelda
If you'd like to see this in action, you can see it here (sorry for the screwy formatting on the plugin code) jsfiddle.net/danesparza/TF6Rb/1Lounging
To improve performance, do a binary search instead of removing 1 character at a time in the "while" loop. If 100% of the text doesn't fit, try 50% of the text; then 75% of the text if 50% fits, or 25% if 50% doesn't fit, etc.Diminish
Really nice! Thanks! One question. Can this work if the textbox height is a percentage of it's parent container? From my tests, it seems to only work when an exact height in pixels is used.Oblast
This works only on block elements. The following changes make it work also on inline elements: 1. add var originalDisplay = el.css('display'); el.css('display', 'block'); before the var t = ... line, 2. add el.css('display', originalDisplay); after the t.remove(); line.Furtado
Added a new answer addressing all of these issues and more: https://mcmap.net/q/37848/-insert-ellipsis-into-html-tag-if-content-too-wideWhittier
I used this script and it is great on desktop browsers but I had to disable it for the iphone as it was causing a javascript timeout. This may have been my use of the script (perhaps applying it to too many elements) but it is worth noting, otherwise worked great.Enrich
Is there a way to make this work when the browser window is resized? I tried setting the width to auto and calling .ellipsis() in resize() but it never shows the ellipses.Peptic
This has some severe performance degradation if you use it on any appreciable number of elements, or the selector matches multiple elements in the DOM.Osteitis
I think that this is not working on select element. Is there a way to achieve this on select element.http://jsfiddle.net/F8Kdt/Hentrich
Can we please, please unmark this answer as correct?Calvinism
At certain width the ellipsis doesn't work. jsfiddle.net/ofrj55j4/28 Try to resize the output window...Armlet
I have forked this to add support for textareas and approximation logic (courtesy of Mikey G's answer): jsfiddle.net/gfullam/j29z7381Guttapercha
do not forget Latin languages and Chinese use different symbol for ellipses ellipsesLatin = '\u2026'; ellipsesChinese = '\u22ef';Studio
P
185

The following CSS only solution for truncating text on a single line works with all browers listed at http://www.caniuse.com as of writing with the exception of Firefox 6.0. Note that JavaScript is totally unnecessary unless you need to support wrapping multiline text or earlier versions of Firefox.

.ellipsis {
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
    -o-text-overflow: ellipsis;
}

If you need support for earlier versions of Firefox check out my answer on this other question.

Pleasance answered 9/7, 2009 at 3:16 Comment(7)
This is orders of magnitude quicker then the jQuery approach. Works fine in IE7+ and Chrome.Penchant
This works well ancient browsers too. We were using it successfully at Google in ~2004, where we were required to support or degrade gracefully on some really corner-case browsers.Nonobservance
JS Fiddle for those that want to sample it on a browser - jsfiddle.net/r39AdCharbonnier
@DilipRajkumar you'll need to provide more detail e.g. a JSFiddle example demonstrating it not working in IE 8.Pleasance
@SimonLieschke: How can we define the no of character after which we want to add ellipsis??Heterosexual
@Heterosexual you don't. Where the text cuts off is dictated by the width of the element containing it, i.e. it truncates when it would overflow the width of the element.Pleasance
Also needs: display: inline-block; width: 150px !important;Confidence
B
120

I've got a solution working in FF3, Safari and IE6+ with single and multiline text

.ellipsis {
    white-space: nowrap;
    overflow: hidden;
}

.ellipsis.multiline {
    white-space: normal;
}

<div class="ellipsis" style="width: 100px; border: 1px solid black;">Lorem ipsum dolor sit amet, consectetur adipisicing elit</div>
<div class="ellipsis multiline" style="width: 100px; height: 40px; border: 1px solid black; margin-bottom: 100px">Lorem ipsum dolor sit amet, consectetur adipisicing elit</div>

<script type="text/javascript" src="/js/jquery.ellipsis.js"></script>
<script type="text/javascript">
$(".ellipsis").ellipsis();
</script>

jquery.ellipsis.js

(function($) {
    $.fn.ellipsis = function()
    {
        return this.each(function()
        {
            var el = $(this);

            if(el.css("overflow") == "hidden")
            {
                var text = el.html();
                var multiline = el.hasClass('multiline');
                var t = $(this.cloneNode(true))
                    .hide()
                    .css('position', 'absolute')
                    .css('overflow', 'visible')
                    .width(multiline ? el.width() : 'auto')
                    .height(multiline ? 'auto' : el.height())
                    ;

                el.after(t);

                function height() { return t.height() > el.height(); };
                function width() { return t.width() > el.width(); };

                var func = multiline ? height : width;

                while (text.length > 0 && func())
                {
                    text = text.substr(0, text.length - 1);
                    t.html(text + "...");
                }

                el.html(t.html());
                t.remove();
            }
        });
    };
})(jQuery);
Bond answered 20/6, 2009 at 22:9 Comment(16)
Nice, I've been looking how to handle overflow with multiple lines. One improvement: instead of appending three periods, append the ellipsis character, '…'.Pleasance
This works very well. You should publish this on the jQuery site.Signor
Although in IE if ellipsis function is applied on a div that just has a link, after ellipsis the link disappears. Any pointers on this?Grizelda
If you'd like to see this in action, you can see it here (sorry for the screwy formatting on the plugin code) jsfiddle.net/danesparza/TF6Rb/1Lounging
To improve performance, do a binary search instead of removing 1 character at a time in the "while" loop. If 100% of the text doesn't fit, try 50% of the text; then 75% of the text if 50% fits, or 25% if 50% doesn't fit, etc.Diminish
Really nice! Thanks! One question. Can this work if the textbox height is a percentage of it's parent container? From my tests, it seems to only work when an exact height in pixels is used.Oblast
This works only on block elements. The following changes make it work also on inline elements: 1. add var originalDisplay = el.css('display'); el.css('display', 'block'); before the var t = ... line, 2. add el.css('display', originalDisplay); after the t.remove(); line.Furtado
Added a new answer addressing all of these issues and more: https://mcmap.net/q/37848/-insert-ellipsis-into-html-tag-if-content-too-wideWhittier
I used this script and it is great on desktop browsers but I had to disable it for the iphone as it was causing a javascript timeout. This may have been my use of the script (perhaps applying it to too many elements) but it is worth noting, otherwise worked great.Enrich
Is there a way to make this work when the browser window is resized? I tried setting the width to auto and calling .ellipsis() in resize() but it never shows the ellipses.Peptic
This has some severe performance degradation if you use it on any appreciable number of elements, or the selector matches multiple elements in the DOM.Osteitis
I think that this is not working on select element. Is there a way to achieve this on select element.http://jsfiddle.net/F8Kdt/Hentrich
Can we please, please unmark this answer as correct?Calvinism
At certain width the ellipsis doesn't work. jsfiddle.net/ofrj55j4/28 Try to resize the output window...Armlet
I have forked this to add support for textareas and approximation logic (courtesy of Mikey G's answer): jsfiddle.net/gfullam/j29z7381Guttapercha
do not forget Latin languages and Chinese use different symbol for ellipses ellipsesLatin = '\u2026'; ellipsesChinese = '\u22ef';Studio
W
40

I built this code using a number of other posts, with the following enhancements:

  1. It uses a binary search to find the text length that is just right.
  2. It handles cases where the ellipsis element(s) are initially hidden by setting up a one-shot show event that re-runs the ellipsis code when the item is first displayed. This is handy for master-detail views or tree-views where some items aren't initially displayed.
  3. It optionally adds a title attribute with the original text for a hoverover effect.
  4. Added display: block to the style, so spans work
  5. It uses the ellipsis character instead of 3 periods.
  6. It auto-runs the script for anything with the .ellipsis class

CSS:

.ellipsis {
        white-space: nowrap;
        overflow: hidden;
        display: block;
}

.ellipsis.multiline {
        white-space: normal;
}

jquery.ellipsis.js

(function ($) {

    // this is a binary search that operates via a function
    // func should return < 0 if it should search smaller values
    // func should return > 0 if it should search larger values
    // func should return = 0 if the exact value is found
    // Note: this function handles multiple matches and will return the last match
    // this returns -1 if no match is found
    function binarySearch(length, func) {
        var low = 0;
        var high = length - 1;
        var best = -1;
        var mid;

        while (low <= high) {
            mid = ~ ~((low + high) / 2); //~~ is a fast way to convert something to an int
            var result = func(mid);
            if (result < 0) {
                high = mid - 1;
            } else if (result > 0) {
                low = mid + 1;
            } else {
                best = mid;
                low = mid + 1;
            }
        }

        return best;
    }

    // setup handlers for events for show/hide
    $.each(["show", "toggleClass", "addClass", "removeClass"], function () {

        //get the old function, e.g. $.fn.show   or $.fn.hide
        var oldFn = $.fn[this];
        $.fn[this] = function () {

            // get the items that are currently hidden
            var hidden = this.find(":hidden").add(this.filter(":hidden"));

            // run the original function
            var result = oldFn.apply(this, arguments);

            // for all of the hidden elements that are now visible
            hidden.filter(":visible").each(function () {
                // trigger the show msg
                $(this).triggerHandler("show");
            });

            return result;
        };
    });

    // create the ellipsis function
    // when addTooltip = true, add a title attribute with the original text
    $.fn.ellipsis = function (addTooltip) {

        return this.each(function () {
            var el = $(this);

            if (el.is(":visible")) {

                if (el.css("overflow") === "hidden") {
                    var content = el.html();
                    var multiline = el.hasClass('multiline');
                    var tempElement = $(this.cloneNode(true))
                        .hide()
                        .css('position', 'absolute')
                        .css('overflow', 'visible')
                        .width(multiline ? el.width() : 'auto')
                        .height(multiline ? 'auto' : el.height())
                    ;

                    el.after(tempElement);

                    var tooTallFunc = function () {
                        return tempElement.height() > el.height();
                    };

                    var tooWideFunc = function () {
                        return tempElement.width() > el.width();
                    };

                    var tooLongFunc = multiline ? tooTallFunc : tooWideFunc;

                    // if the element is too long...
                    if (tooLongFunc()) {

                        var tooltipText = null;
                        // if a tooltip was requested...
                        if (addTooltip) {
                            // trim leading/trailing whitespace
                            // and consolidate internal whitespace to a single space
                            tooltipText = $.trim(el.text()).replace(/\s\s+/g, ' ');
                        }

                        var originalContent = content;

                        var createContentFunc = function (i) {
                            content = originalContent.substr(0, i);
                            tempElement.html(content + "…");
                        };

                        var searchFunc = function (i) {
                            createContentFunc(i);
                            if (tooLongFunc()) {
                                return -1;
                            }
                            return 0;
                        };

                        var len = binarySearch(content.length - 1, searchFunc);

                        createContentFunc(len);

                        el.html(tempElement.html());

                        // add the tooltip if appropriate
                        if (tooltipText !== null) {
                            el.attr('title', tooltipText);
                        }
                    }

                    tempElement.remove();
                }
            }
            else {
                // if this isn't visible, then hook up the show event
                el.one('show', function () {
                    $(this).ellipsis(addTooltip);
                });
            }
        });
    };

    // ellipsification for items with an ellipsis
    $(document).ready(function () {
        $('.ellipsis').ellipsis(true);
    });

} (jQuery));
Whittier answered 30/1, 2012 at 21:54 Comment(7)
Beautiful. Bravo for implementing my suggestion of a binary search.Diminish
Just a quick note... it's worth adding .css('max-width', 'none') to the tempElement var... This way you can use a max-width declaration in your css, making the plugin far more flexible (at least for most use cases I have). Nice work anyway. :)Melbamelborn
This is a much quicker implementation than the above accepted answer. If you have multiple .ellipsis elements, and are doing anything dynamic with them, this one performs much better.Therein
Can you please provide an example? My question is here: #26345020Armlet
Binary Search is preferable but not with very small datasets and is in this case it hinders performance in comparison to a straight linear search such as indexOf() ... apparentlyWiry
@Wiry In this particular instance, I would have to disagree. At each step in the binary search, it is creating the substring, making HTML of it and measuring it. The measuring is an expensive operation which should be minimized.Whittier
@AdamTegen : Thanks for nice plugin. have a question, what if we need it for the 4th or 5th line ? pl. replayMenedez
J
20

My answer only supports single line text. Check out gfullam's comment below for the multi-line fork, it looks pretty promising.

I rewrote the code from the first answer a few times, and I think this should be the fastest.

It first finds an "Estimated" text length, and then adds or removes a character until the width is correct.

The logic it uses is shown below:

enter image description here

After an "estimated" text length is found, characters are added or removed until the desired width is reached.

I'm sure it needs some tweaking, but here's the code:

(function ($) {
    $.fn.ellipsis = function () {
        return this.each(function () {
            var el = $(this);

            if (el.css("overflow") == "hidden") {
                var text = el.html().trim();
                var t = $(this.cloneNode(true))
                                        .hide()
                                        .css('position', 'absolute')
                                        .css('overflow', 'visible')
                                        .width('auto')
                                        .height(el.height())
                                        ;
                el.after(t);

                function width() { return t.width() > el.width(); };

                if (width()) {

                    var myElipse = "....";

                    t.html(text);

                    var suggestedCharLength = (text.length * el.width() / t.width()) - myElipse.length;

                    t.html(text.substr(0, suggestedCharLength) + myElipse);

                    var x = 1;
                    if (width()) {
                        while (width()) {
                            t.html(text.substr(0, suggestedCharLength - x) + myElipse);
                            x++;
                        }
                    }
                    else {
                        while (!width()) {
                            t.html(text.substr(0, suggestedCharLength + x) + myElipse);
                            x++;
                        }
                        x--;
                        t.html(text.substr(0, suggestedCharLength + x) + myElipse);
                    }

                    el.html(t.html());
                    t.remove();
                }
            }
        });
    };
})(jQuery);
Jig answered 24/2, 2012 at 18:54 Comment(2)
Your solution may not be the best, but it's very well explained. And I like this type of approximation logic. +1 :)Harvester
I have forked this to add support for textareas and multiline (vertical) ellipsis truncation: jsfiddle.net/gfullam/j29z7381 (I like the approximation logic BTW)Guttapercha
L
20

Just in case y'all end up here in 2013 - here is a pure css approach I found here: http://css-tricks.com/snippets/css/truncate-string-with-ellipsis/

.truncate {
  width: 250px;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

It works well.

Ligula answered 24/10, 2013 at 19:17 Comment(1)
FWIW, text-overflow doesn't work with textarea elements (as of 2015). If you need support for textarea you can achieve it by modifying the accepted answer or by using this fork of it.Guttapercha
F
18

I made a really cool jQuery plugin for handling all varieties of ellipsis of text is one called ThreeDots @ http://tpgblog.com/threedots

It's much more flexible than the CSS approaches, and supports much more advanced, customizable behaviors and interactions.

Enjoy.

Fagan answered 26/12, 2009 at 6:44 Comment(0)
B
8

A more flexible jQuery plugin enabling you to keep a element after the ellipsis (for example a "read-more" button) and update onWindowResize. It also works around text with markup:

http://dotdotdot.frebsite.nl

Bourguiba answered 11/10, 2011 at 13:24 Comment(1)
I just tested this plugin, but I couldn't make it work. Trunk8 was a better choice for me.Southbound
P
8

trunk8 jQuery plugin supports multiple lines, and can use any html, not just ellipsis characters, for the truncation suffix: https://github.com/rviscomi/trunk8

Demo here: http://jrvis.com/trunk8/

Protuberate answered 24/8, 2012 at 8:55 Comment(2)
yeah but this is ancient now. looks like its not supported?Delozier
It looks like its actively supported - at time of writing (March 2016), the issues and PRs show recent activity involving the project creator.Protuberate
S
5

There's actually a pretty straightforward way to do this in CSS exploiting the fact that IE extends this with non-standards and FF supports :after

You can also do this in JS if you wish by inspecting the scrollWidth of the target and comparing it to it's parents width, but imho this is less robust.

Edit: this is apparently more developed than I thought. CSS3 support may soon exist, and some imperfect extensions are available for you to try.

That last one is good reading.

Sendoff answered 11/2, 2009 at 14:6 Comment(1)
Actually I prefer the JS solution - because it only adds "..." if the text is wider than the available space.Unguarded
R
3

Well, one simple solution, that doesn't quite add the "...", but does prevent the <h2> from breaking into two lines would be to add this bit of css:

h2 {
    height:some_height_in_px; /* this is the height of the line */
    overflow:hidden; /* so that the second (or third, fourth, etc.)
                        line is not visible */
}

I gave it some more thought, and I came up with this solution, you have to wrap the textual contents of your h2 tag with another tag (e.g. a span) (or alternatively wrap the h2s with something that has the given height) and then you can use this sort of javascript to filter out the unneeded words:

var elems = document.getElementById('conainter_of_h2s').
                     getElementsByTagName('h2');

    for ( var i = 0, l = elems.length; i < l; i++) {
        var span = elems.item(i).getElementsByTagName('span')[0];
        if ( span.offsetHeight > elems.item(i).offsetHeight ) {
            var text_arr = span.innerHTML.split(' ');
            for ( var j = text_arr.length - 1; j>0 ; j--) {
                delete text_arr[j];
                span.innerHTML = text_arr.join(' ') + '...';
                if ( span.offsetHeight <= 
                                        elems.item(i).offsetHeight ){
                    break;
                }
            }
        }
    }
Runthrough answered 11/2, 2009 at 13:58 Comment(1)
Actually I thought about using this as a basis for a possible solution, but I have no idea if - based on this - it would be possible to find out, if the whole text is now displayed or if I need to shorten it and add "...". Just cutting it off would look weird.Unguarded
B
3

I'd done something similar for a client recently. Here's a version of what I did for them (example tested in all latest browser versions on Win Vista). Not perfect all around the board, but could be tweaked pretty easily.

Demo: http://enobrev.info/ellipsis/

Code:

<html>
    <head>
        <script src="http://www.google.com/jsapi"></script>
        <script>            
            google.load("jquery", "1.2.6");
            google.setOnLoadCallback(function() {
                $('.longtext').each(function() {
                    if ($(this).attr('scrollWidth') > $(this).width()) {
                        $more = $('<b class="more">&hellip;</b>');

                        // add it to the dom first, so it will have dimensions
                        $(this).append($more);

                        // now set the position
                        $more.css({
                            top: '-' + $(this).height() + 'px',
                            left: ($(this).attr('offsetWidth') - $more.attr('offsetWidth')) + 'px'
                        });
                    }
                });
            });
        </script>

        <style>
            .longtext {
                height: 20px;
                width: 300px;
                overflow: hidden;
                white-space: nowrap;
                border: 1px solid #f00;
            }

            .more {
                z-index: 10;
                position: relative;
                display: block;
                background-color: #fff;
                width: 18px;
                padding: 0 2px;
            }
        </style>
    </head>
    <body>
        <p class="longtext">This is some really long text.  This is some really long text.  This is some really long text.  This is some really long text.</p>
    </body>
</html>
Brazier answered 11/2, 2009 at 14:34 Comment(0)
B
3

Here's another JavaScript solution. Works very good and very fast.

https://github.com/dobiatowski/jQuery.FastEllipsis

Tested on Chrome, FF, IE on Windows and Mac.

Borough answered 19/1, 2012 at 12:29 Comment(1)
While this is less automatic, I found it to be a more accurate solution than Adam Tegen's answer. This script requires that the maximum number of lines of text be specified instead of guessing.Booby
L
3

There's a solution for multi-line text with pure css. It's called line-clamp, but it only works in webkit browsers. There is however a way to mimic this in all modern browsers (everything more recent than IE8.) Also, it will only work on solid backgrounds because you need a background-image to hide the last words of the last line. Here's how it goes:

Given this html:

<p class="example" id="example-1">
    Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.
</p>

Here's the CSS:

p {
    position:relative;
    line-height:1.4em;
    height:4.2em;      /* 3 times the line-height to show 3 lines */
}
p::after {
    content:"...";
    font-weight:bold;
    position:absolute;
    bottom:0;
    right:0;
    padding:0 20px 1px 45px;
    background:url(ellipsis_bg.png) repeat-y;
}

ellipsis_bg.png being an image of the same color of your background, that would be about 100px wide and have the same height as your line-height.

It's not very pretty, as your text may be cut of in the middle of a letter, but it may be useful in some cases.

Reference: http://www.css-101.org/articles/line-clamp/line-clamp_for_non_webkit-based_browsers.php

Lozano answered 25/8, 2013 at 10:0 Comment(2)
That's nice, but you need to be sure that your text is long enough, because this CSS will add "..." even if the text is short enough to fit into the available space. BTW: Same answer has been provided by Apopii about a month ago ;)Unguarded
@Unguarded Pretty much the same indeed. But I think the gradient trick is neat and this code in CSS instead of SASS, so I think it's worthy to be a separate answer.Lozano
S
3

Pure CSS Multi-line Ellipsis for text content:

.container{
    position: relative;  /* Essential */
    background-color: #bbb;  /* Essential */
    padding: 20px; /* Arbritrary */
}
.text {
    overflow: hidden;  /* Essential */
    /*text-overflow: ellipsis; Not needed */
    line-height: 16px;  /* Essential */
    max-height: 48px; /* Multiples of line-height */
}
.ellipsis {
    position: absolute;/* Relies on relative container */
    bottom: 20px; /* Matches container padding */
    right: 20px; /* Matches container padding */
    height: 16px; /* Matches line height */
    width: 30px; /* Arbritrary */
    background-color: inherit; /* Essential...or specify a color */
    padding-left: 8px; /* Arbritrary */
}
<div class="container">
    <div class="text">
        Lorem ipsum dolor sit amet, consectetur eu in adipiscing elit. Aliquam consectetur venenatis blandit. Praesent vehicula, libero non pretium vulputate, lacus arcu facilisis lectus, sed feugiat tellus nulla eu dolor. Nulla porta bibendum lectus quis euismod. Aliquam volutpat ultricies porttitor. Cras risus nisi, accumsan vel cursus ut, sollicitudin vitae dolor. Fusce scelerisque eleifend lectus in bibendum. Suspendisse lacinia egestas felis a volutpat. Aliquam volutpat ultricies porttitor. Cras risus nisi, accumsan vel cursus ut, sollicitudin vitae dolor. Fusce scelerisque eleifend lectus in bibendum. Suspendisse lacinia egestas felis a volutpat.
    </div>
    <div class="ellipsis">...</div>
</div>

Please checkout the snippet for a live example.

Shilling answered 19/6, 2015 at 20:54 Comment(0)
U
2

There is a simple jQuery solution by Devon Govett:

https://gist.github.com/digulla/5796047

To use, just call ellipsis() on a jQuery object. For example:

$("span").ellipsis();

Unguarded answered 15/4, 2009 at 12:33 Comment(3)
I was just about to post the same link. :)Entero
The link in this post is dead.Thimbleweed
I added a fallback linkUnguarded
V
2

This is similar to Alex's but does it in log time instead of linear, and takes a maxHeight parameter.

jQuery.fn.ellipsis = function(text, maxHeight) {
  var element = $(this);
  var characters = text.length;
  var step = text.length / 2;
  var newText = text;
  while (step > 0) {
    element.html(newText);
    if (element.outerHeight() <= maxHeight) {
      if (text.length == newText.length) {
        step = 0;
      } else {
        characters += step;
        newText = text.substring(0, characters);
      }
    } else {
      characters -= step;
      newText = newText.substring(0, characters);
    }
    step = parseInt(step / 2);
  }
  if (text.length > newText.length) {
    element.html(newText + "...");
    while (element.outerHeight() > maxHeight && newText.length >= 1) {
      newText = newText.substring(0, newText.length - 1);
      element.html(newText + "...");
    }
  }
};
Vaccine answered 18/5, 2010 at 16:54 Comment(0)
C
1

I rewrote Alex's function to use to the MooTools library. I changed it a bit to word jump rather than add the ellipsis in the middle of a word.

Element.implement({
ellipsis: function() {
    if(this.getStyle("overflow") == "hidden") {
        var text = this.get('html');
        var multiline = this.hasClass('multiline');
        var t = this.clone()
            .setStyle('display', 'none')
            .setStyle('position', 'absolute')
            .setStyle('overflow', 'visible')
            .setStyle('width', multiline ? this.getSize().x : 'auto')
            .setStyle('height', multiline ? 'auto' : this.getSize().y)
            .inject(this, 'after');

        function height() { return t.measure(t.getSize).y > this.getSize().y; };
        function width() { return t.measure(t.getSize().x > this.getSize().x; };

        var func = multiline ? height.bind(this) : width.bind(this);

        while (text.length > 0 && func()) {
            text = text.substr(0, text.lastIndexOf(' '));
            t.set('html', text + "...");
        }

        this.set('html', t.get('html'));
        t.dispose();
    }
}
});
Crepuscular answered 5/1, 2011 at 18:28 Comment(0)
S
1

I couldn't find a script that worked exactly as I wanted it so did my own for jQuery - quite a few options to set with more on their way :)

https://github.com/rmorse/AutoEllipsis

Seascape answered 25/10, 2011 at 12:25 Comment(0)
S
1

I was a bit surprised by the behavior of the css though.

var cssEllipsis = 
{   "width": "100%","display": "inline-block", 
"vertical-align": "middle", "white-space": "nowrap", 
"overflow": "hidden", "text-overflow": "ellipsis" 
};

Unless I provided the width to the control to which i needed to bind the ellipsis didn't suppost my cause. Is width a must property to be added ??? Please put your thoughts.

Suicide answered 16/1, 2012 at 13:4 Comment(0)
G
1

DO THE ELLIPSIS USING ONLY CSS

<html>
<head>
<style type="text/css">
#ellipsisdiv {
    width:200px;
    white-space: nowrap;  
    overflow: hidden;  
    text-overflow: ellipsis;  
}  
</style>
</head>
<body>
<div id="ellipsisdiv">
This content is more than 200px and see how the the ellipsis comes at the end when the content width exceeds the div width.
</div>
</body>
</html>

*This code works on most current browsers. If you experience any problem with Opera and IE (which probably you won't), add these in the style:

-o-text-overflow: ellipsis;  
-ms-text-overflow: ellipsis;

* This feature is part of CSS3. Its complete syntax is:

text-overflow: clip|ellipsis|string;
Gramophone answered 18/1, 2012 at 13:26 Comment(0)
L
1

Here is a nice widget/plugin library which has ellipsis built in: http://www.codeitbetter.co.uk/widgets/ellipsis/ All you need to do it reference the library and call the following:

<script type="text/javascript"> 
   $(document).ready(function () { 
      $(".ellipsis_10").Ellipsis({ 
         numberOfCharacters: 10, 
         showLessText: "less", 
         showMoreText: "more" 
      }); 
   }); 
</script> 
<div class="ellipsis_10"> 
   Some text here that's longer than 10 characters. 
</div>
Liponis answered 7/4, 2012 at 14:55 Comment(0)
S
1

you can do this much easier with css only, for example : sass mode

.truncatedText {
   font-size: 0.875em;
   line-height: 1.2em;
   height: 2.4em; // 2 lines * line-height
   &:after {
      content: " ...";
   }
}

and you have ellipsis ;)

Staples answered 27/6, 2013 at 14:3 Comment(0)
S
0

Just like @acSlater I couldn't find something for what I needed so I rolled my own. Sharing in case anyone else can use:

Method:
ellipsisIfNecessary(mystring,maxlength);
Usage:
trimmedString = ellipsisIfNecessary(mystring,50);
Code and Demo Link: https://gist.github.com/cemerson/10368014
Snicker answered 10/4, 2014 at 10:48 Comment(4)
Two annotations: a) This code does not check the actual size of a HTML element. You need to specify a given length - which may be the required functionality, but is actually trivial to do. b) You just add "..." to the end of the string. There is an ellipsis sign "…" you could/should use.Unguarded
Hey @Unguarded - the code actually does check the length against the maxlength parameter. It's working for me at least. That said - this is just my humble one-off for my particular situation. Feel free to use any of the above solutions if this one doesn't work right for your situation.Snicker
Yes, it works with a "length", but not with a "width" (pixel size).Unguarded
Interesting idea - feel free to make an updated version w/support for that. I don't need that now but could be useful in future.Snicker
P
0
<html>
<head>
    <!-- By Warren E. Downs, copyright 2016.  Based loosely on a single/multiline JQuery using example by Alex,
    but optimized to avoid JQuery, to use binary search, to use CSS text-overflow: ellipsis for end,
    and adding marquee option as well.
    Credit: Marquee: http://jsfiddle.net/jonathansampson/xxuxd/
            JQuery version: https://mcmap.net/q/37848/-insert-ellipsis-into-html-tag-if-content-too-wide
            (by Alex, http://stackoverflow.com/users/71953/alex)
            (Improved with Binary Search as suggested by StanleyH, http://stackoverflow.com/users/475848/stanleyh)
    -->
    <meta content="text/html;charset=utf-8" http-equiv="Content-Type">
    <meta content="utf-8" http-equiv="encoding">
    <style>

        .single {
            overflow:hidden;
            white-space: nowrap;
            width: 10em;
            padding: 10px;
            margin: 0 auto;
            border: solid 1px blue;
        }

        .multiline {
            overflow: hidden;
            white-space: wrap;
            width: 10em;
            height: 4.5em;
            padding: 10px;
            margin: 0 auto;
            border: solid 1px blue;
        }

        .marquee {
            overflow: hidden;
            width: 40em;
            padding: 10px;
            margin: 0 auto;
            border: solid 1px blue;
        }

</style>
    <script>
        var _marqueeNumber=0;
        // mode=start,end,middle
        function clipText(text, len, mode) {
            if(!mode) { mode="end"; }
            else { mode=mode.toLowerCase(); }
            if(mode == "start") { return "&hellip;"+clipText(text,len,"_start"); }
            if(mode == "_start") { return text.substr(text.length - len); }
            if(mode == "middle") { 
                return clipText(text, len/2, "end") + clipText(text, len/2, "_start");
            }
            return text.substr(0, len) + "&hellip;";
        }

        function generateKeyframes(clsName, start, end) {
            var sec=5;
            var totalLen=parseFloat(start)-parseFloat(end);
            if(start.indexOf('em') > -1)      { sec=Math.round(totalLen/3); }
            else if(start.indexOf('px') > -1) { sec=Math.round(totalLen/42); }

            var style = document.createElement('style');
            style.type = 'text/css';
            style.innerHTML = 'body {}';
            document.getElementsByTagName('head')[0].appendChild(style);
            this.stylesheet = document.styleSheets[document.styleSheets.length-1];
            try {
                this.stylesheet.insertRule('.'+clsName+' {\n'+
                    '    animation: '+clsName+' '+sec+'s linear infinite;\n'+
                    '}\n', this.stylesheet.rules.length);
                this.stylesheet.insertRule('.'+clsName+':hover {\n'+
                    '    animation-play-state: paused\n'+
                    '}\n', this.stylesheet.rules.length);
                this.stylesheet.insertRule('@keyframes '+clsName+' {\n'+
                    '    0%   { text-indent: '+start+' }\n'+
                    '    100% { text-indent: '+end+' }\n'+
                    '}', this.stylesheet.rules.length);
            } catch (e) {
                console.log(e.message);
            }
        }

        function addClone(el, multiline, estyle) {
            if(!estyle) { 
                try { estyle=window.getComputedStyle(el); }
                catch(e) { return null; }
            }
            var t = el.cloneNode(true);
            var s=t.style;
            //s.display='none';
            s.visibility='hidden'; // WARNING: Infinite loop if this is not hidden (e.g. while testing)
            s.display='inline-block';
            s.background='black';
            s.color='white';
            s.position='absolute';
            s.left=0;
            s.top=0;
            s.overflow='visible';
            s.width=(multiline ? parseFloat(estyle.width) : 'auto');
            s.height=(multiline ? 'auto' : parseFloat(estyle.height));

            el.parentNode.insertBefore(t, el.nextSibling);

            return t;
        }
        function getTextWidth(el, multiline) {
            var t=addClone(el, multiline);
            if(!t) { return null; }
            var ts=window.getComputedStyle(t);
            var w=ts.width;
            if(multiline) {
                var es=window.getComputedStyle(el);
                var lines=Math.round(parseInt(ts.height)/parseInt(es.height))*2+0.5;
                w=w+'';
                var unit=''; // Extract unit
                for(var xa=0; xa<w.length; xa++) {
                    var c=w[xa];
                    if(c <= '0' || c >= '9') { unit=w.substr(xa-1); }
                }
                w=parseFloat(w);
                w*=lines; // Multiply by lines
                w+=unit; // Append unit again
            }
            t.parentNode.removeChild(t);
            return w;
        }

        // cls=class of element to ellipsize
        // mode=start,end,middle,marq (scrolling marquee instead of clip)
        function ellipsis(cls, mode) {
            mode=mode.toLowerCase();
            var elems=document.getElementsByClassName(cls);
            for(xa in elems) {
                var el=elems[xa];
                var multiline = el.className ? el.className.indexOf('multiline') > -1 : true;
                if(mode == "marq") {       
                    var w=getTextWidth(el, multiline);
                    if(!w) { continue; }
                    var mCls="dsmarquee"+(_marqueeNumber++);
                    var es=window.getComputedStyle(el);
                    generateKeyframes(mCls,es.width, '-'+w);
                    el.className+=" "+mCls; 
                    continue; 
                }
                if(mode == "end" && !multiline) { el.style.textOverflow="ellipsis"; continue; }
                var estyle=null;
                try { estyle=window.getComputedStyle(el); }
                catch(e) { continue; }
                if(estyle.overflow == "hidden") {
                    var text = el.innerHTML;
                    var t=addClone(el, multiline, estyle);

                    function height() {
                        var ts=window.getComputedStyle(t);
                        var es=window.getComputedStyle(el);
                        return parseFloat(ts.height) - parseFloat(es.height); 
                    }
                    function width() { 
                        var ts=window.getComputedStyle(t);
                        var es=window.getComputedStyle(el);
                        return parseFloat(ts.width) - parseFloat(es.width); 
                    }

                    var tooLong = multiline ? height : width;

                    var len=text.length;
                    var diff=1;
                    var olen=0;
                    var jump=len/2;
                    while (len > 0) {
                        var diff=tooLong();
                        if(diff > 0) { len-=jump; jump/=2; }
                        else if(diff < 0) { len+=jump; }
                        len=Math.round(len);
                        //alert('len='+len+';olen='+olen+';diff='+diff+';jump='+jump+';t='+JSON.stringify(t.innerHTML));
                        t.innerHTML=clipText(text, len, mode);
                        if(olen == len) { break; }
                        olen=len;
                    }
                    el.innerHTML=t.innerHTML;
                    t.parentNode.removeChild(t);
                }           
                //break;
                t.style.visibility='hidden';
            }
        }

        function testHarness() {
            ellipsis('ellipsis1', 'start'); 
            ellipsis('ellipsis2', 'end'); 
            ellipsis('ellipsis3', 'middle'); 
            ellipsis('marquee', 'marq')
        }
    </script>
    </head>
    <body onload="testHarness()">
    <div class="single ellipsis1" style="float:left">some long text that should be clipped left</div>
    <div class="single ellipsis2" style="float:right">right clip long text that should be clipped</div>
    <div class="single ellipsis3" style="float:center">some long text that should be clipped in the middle</div>

    <br />

    <p class="single marquee">Windows 8 and Windows RT are focused on your life—your friends and family, your apps, and your stuff. With new things like the <a href="http://windows.microsoft.com/en-US/windows-8/start-screen">Start screen</a>, <a href="http://windows.microsoft.com/en-US/windows-8/charms">charms</a>, and a <a href="http://windows.microsoft.com/en-US/windows-8/microsoft-account">Microsoft account</a>, you can spend less time searching and more time doing.</p>
    &nbsp;

    <br />

    <div class="multiline ellipsis1" style="float:left">Test test test test test test, some more long text, such as asdasdasdasdasd, that should be multiline clipped left(*)</div>

    <div class="multiline ellipsis2" style="float:right">right clip multiline long text, such as Test test test test test test, and some more long text that should be multiline clipped right.</div>

    <div class="multiline ellipsis3" style="float:center">Test test test test test test, some more long text, such as asdasdasdasdasd, that should be multiline clipped in the middle(*)</div>

    <br />

    <p class="multiline marquee">Multiline Marquee: Windows 8 and Windows RT are focused on your life—your friends and family, your apps, and your stuff. With new things like the <a href="http://windows.microsoft.com/en-US/windows-8/start-screen">Start screen</a>, <a href="http://windows.microsoft.com/en-US/windows-8/charms">charms</a>, and a <a href="http://windows.microsoft.com/en-US/windows-8/microsoft-account">Microsoft account</a>, you can spend less time searching and more time doing.</p>
    &nbsp;

    </body>
</html>
Phenomena answered 21/5, 2016 at 1:8 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.