Inserte puntos suspensivos (...) en la etiqueta HTML si el contenido es demasiado ancho


148

Tengo una página web con un diseño elástico que cambia su ancho si la ventana del navegador cambia de tamaño.

En este diseño hay titulares ( h2) que tendrán una longitud variable (en realidad son titulares de publicaciones de blog sobre los que no tengo control). Actualmente, si son más anchas que la ventana, se dividen en dos líneas.

¿Existe una solución elegante y probada (cross-browser), por ejemplo con jQuery, que acorta el HTML interno de esa etiqueta de título y agrega "..." si el texto fuera demasiado ancho para caber en una línea en la pantalla actual / ancho del contenedor?


1
Respuesta actualizada 2014: stackoverflow.com/a/22811590/759452
Adrien Be

He creado un complemento basado en este hilo que utiliza las propiedades CSS de espacio en blanco y ajuste de texto para formatear el texto. github.com/nothrem/jQuerySmartEllipsis
Radek Pech

Respuestas:


119

Tengo una solución que funciona en FF3, Safari e IE6 + con texto simple y multilínea

.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);

22
Bien, he estado buscando cómo manejar el desbordamiento con múltiples líneas. Una mejora: en lugar de agregar tres puntos, agregue el carácter de puntos suspensivos, '...'.
Simon Lieschke

44
Esto funciona muy bien Debe publicar esto en el sitio jQuery.
Edgar

1
Aunque en IE si la función de puntos suspensivos se aplica en un div que solo tiene un enlace, después de puntos suspensivos el enlace desaparece. ¿Algún indicador sobre esto?
Chantz

66
Si desea ver esto en acción, puede verlo aquí (perdón por el formato atornillado
Dan Esparza

22
Para mejorar el rendimiento, realice una búsqueda binaria en lugar de eliminar 1 carácter a la vez en el ciclo "while". Si el 100% del texto no se ajusta, intente con el 50% del texto; luego 75% del texto si el 50% se ajusta, o el 25% si el 50% no se ajusta, etc.
StanleyH

182

La siguiente solución CSS única para truncar texto en una sola línea funciona con todos los navegadores enumerados en http://www.caniuse.com a partir de la escritura, con la excepción de Firefox 6.0. Tenga en cuenta que JavaScript es totalmente innecesario a menos que necesite admitir el ajuste de texto multilínea o versiones anteriores de Firefox.

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

Si necesita soporte para versiones anteriores de Firefox, consulte mi respuesta sobre esta otra pregunta .


2
Esto es un orden de magnitud más rápido que el enfoque jQuery. Funciona bien en IE7 + y Chrome.
JDB todavía recuerda a Mónica el

3
Esto funciona bien en navegadores antiguos también. Lo utilizamos con éxito en Google en ~ 2004, donde se nos exigió que admitiéramos o degradamos con gracia en algunos navegadores realmente curiosos.
ElBel

2
JS Fiddle para aquellos que quieran probarlo
Deepak Bala

@DilipRajkumar deberá proporcionar más detalles, por ejemplo, un ejemplo de JSFiddle que demuestre que no funciona en IE 8.
Simon Lieschke

1
@SharpCoder no lo haces. Donde el texto se corta está dictado por el ancho del elemento que lo contiene, es decir, se trunca cuando se desbordaría el ancho del elemento.
Simon Lieschke

40

Construí este código usando otras publicaciones, con las siguientes mejoras:

  1. Utiliza una búsqueda binaria para encontrar la longitud de texto correcta.
  2. Maneja casos en los que los elementos de puntos suspensivos se ocultan inicialmente configurando un evento de muestra de una sola vez que vuelve a ejecutar el código de puntos suspensivos cuando el elemento se muestra por primera vez. Esto es útil para vistas de detalles maestros o vistas de árbol donde algunos elementos no se muestran inicialmente.
  3. Opcionalmente agrega un atributo de título con el texto original para un efecto de desplazamiento.
  4. Agregado display: blockal estilo, por lo que abarca el trabajo
  5. Utiliza el carácter de puntos suspensivos en lugar de 3 puntos.
  6. Ejecuta automáticamente el script para cualquier cosa con la clase .ellipsis

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));

2
Hermoso. Bravo por implementar mi sugerencia de una búsqueda binaria.
StanleyH

2
Solo una nota rápida ... vale la pena agregar .css ('max-width', 'none') a tempElement var ... De esta manera, puede usar una declaración de ancho máximo en su css, haciendo que el complemento sea mucho más flexible (Al menos para la mayoría de los casos de uso que tengo). Buen trabajo de todos modos. :)
gordyr

3
Esta es una implementación mucho más rápida que la respuesta aceptada anteriormente. Si tiene múltiples elementos .ellipsis y está haciendo algo dinámico con ellos, este se desempeña mucho mejor.
mjvotaw

¿Puedes por favor dar un ejemplo? Mi pregunta está aquí: stackoverflow.com/questions/26344520/…
SearchForKnowledge

La búsqueda binaria es preferible pero no con conjuntos de datos muy pequeños y, en este caso, dificulta el rendimiento en comparación con una búsqueda lineal directa como indexOf () ... aparentemente
user1360809

20

Mi respuesta solo admite texto de una sola línea. Mira el comentario de gfullam a continuación para la bifurcación de varias líneas, parece bastante prometedor.

Reescribí el código de la primera respuesta varias veces, y creo que este debería ser el más rápido.

Primero encuentra una longitud de texto "Estimada" y luego agrega o elimina un carácter hasta que el ancho sea correcto.

La lógica que utiliza se muestra a continuación:

ingrese la descripción de la imagen aquí

Después de encontrar una longitud de texto "estimada", los caracteres se agregan o eliminan hasta alcanzar el ancho deseado.

Estoy seguro de que necesita algunos ajustes, pero aquí está el código:

(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);

3
Puede que su solución no sea la mejor, pero está muy bien explicada. Y me gusta este tipo de lógica de aproximación. +1 :)
Flater

2
He bifurcado esto para agregar soporte para áreas de texto y truncamiento de puntos suspensivos multilínea (vertical): jsfiddle.net/gfullam/j29z7381 (Me gusta la lógica de aproximación por cierto)
gfullam


18

Hice un plugin jQuery realmente genial para manejar todas las variedades de puntos suspensivos de texto, uno llamado ThreeDots @ http://tpgblog.com/threedots

Es mucho más flexible que los enfoques CSS, y admite comportamientos e interacciones mucho más avanzados y personalizables.

Disfrutar.


8

Un complemento jQuery más flexible que le permite mantener un elemento después de los puntos suspensivos (por ejemplo, un botón "leer más") y actualizar onWindowResize. También funciona alrededor del texto con marcado:

http://dotdotdot.frebsite.nl


Acabo de probar este complemento, pero no pude hacerlo funcionar. Trunk8 fue una mejor opción para mí.
Guilherme Garnier

8

El complemento trunk8 jQuery admite varias líneas y puede usar cualquier html, no solo caracteres de elipsis, para el sufijo de truncamiento: https://github.com/rviscomi/trunk8

Demostración aquí: http://jrvis.com/trunk8/


Sí, pero esto es antiguo ahora. parece que no es compatible?
user2513846

1
Parece que está respaldado activamente: al momento de escribir (marzo de 2016), los problemas y las relaciones públicas muestran actividad reciente que involucra al creador del proyecto.
Eliot Sykes

5

En realidad, hay una manera bastante sencilla de hacer esto en CSS aprovechando el hecho de que IE extiende esto con soporte no estándar y FF:after

También puede hacer esto en JS si lo desea inspeccionando el ancho de desplazamiento del objetivo y comparándolo con el ancho de sus padres, pero en mi opinión, esto es menos robusto.

Editar: esto aparentemente está más desarrollado de lo que pensaba. El soporte CSS3 puede existir pronto, y algunas extensiones imperfectas están disponibles para que las pruebe.

Ese último es una buena lectura.


En realidad, prefiero la solución JS, porque solo agrega "..." si el texto es más ancho que el espacio disponible.
BlaM

3

Había hecho algo similar para un cliente recientemente. Aquí hay una versión de lo que hice por ellos (ejemplo probado en todas las últimas versiones de navegador en Win Vista). No es perfecto en todos los ámbitos, pero podría modificarse con bastante facilidad.

Demostración: http://enobrev.info/ellipsis/

Código:

<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>

3

Bueno, una solución simple, que no agrega el "...", pero evita que el <h2> se rompa en dos líneas sería agregar este bit de 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 */
}

Pensé un poco más, y se me ocurrió esta solución, tienes que envolver el contenido textual de tu etiqueta h2 con otra etiqueta (por ejemplo, un lapso) (o alternativamente envolver los h2 con algo que tenga la altura dada) y luego puedes usar este tipo de javascript para filtrar las palabras innecesarias:

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;
                }
            }
        }
    }

En realidad, pensé en usar esto como base para una posible solución, pero no tengo idea si, en base a esto, sería posible averiguar si ahora se muestra todo el texto o si necesito acortarlo y agregar " ... ". Solo cortarlo se vería raro.
BlaM


3

Hay una solución para texto de varias líneas con CSS puro. Se llama line-clamp, pero solo funciona en los navegadores webkit. Sin embargo, hay una manera de imitar esto en todos los navegadores modernos (todo más reciente que IE8). Además, solo funcionará en fondos sólidos porque necesita una imagen de fondo para ocultar las últimas palabras de la última línea. Así es como va:

Dado este 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>

Aquí está el 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 es una imagen del mismo color de fondo, que tendría aproximadamente 100 píxeles de ancho y la misma altura que la altura de la línea.

No es muy bonito, ya que su texto puede estar cortado en el medio de una carta, pero puede ser útil en algunos casos.

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


Eso es bueno, pero debe asegurarse de que su texto sea lo suficientemente largo, porque este CSS agregará "..." incluso si el texto es lo suficientemente corto como para caber en el espacio disponible. Por cierto: Apopii proporcionó la misma respuesta hace aproximadamente un mes;)
BlaM

@BlaM Más o menos lo mismo. Pero creo que el truco del gradiente es ordenado y este código en CSS en lugar de SASS, por lo que creo que vale la pena ser una respuesta separada.
Jules Colle

3

Puntos suspensivos de CSS multilínea pura para contenido de texto:

.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>

Consulte el fragmento para ver un ejemplo en vivo.


2

Esto es similar al de Alex, pero lo hace en tiempo de registro en lugar de lineal, y toma un parámetro maxHeight.

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 + "...");
    }
  }
};


1

Reescribí la función de Alex para usar en la biblioteca MooTools. Lo cambié un poco a salto de palabra en lugar de agregar puntos suspensivos en el medio de una palabra.

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();
    }
}
});


1

Sin embargo, me sorprendió un poco el comportamiento del CSS.

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

A menos que proporcione el ancho al control al que necesitaba unir los puntos suspensivos, no supuse mi causa. ¿Es el ancho una propiedad imprescindible para agregarse? Por favor, pon tus pensamientos.


1

HAGA LA ELIPSIS USANDO SOLO 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>

* Este código funciona en la mayoría de los navegadores actuales. Si tiene algún problema con Opera e IE (que probablemente no tendrá), agréguelos al estilo:

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

* Esta característica es parte de CSS3. Su sintaxis completa es:

text-overflow: clip|ellipsis|string;

1

Aquí hay una buena biblioteca de widgets / complementos que tiene puntos suspensivos incorporados: http://www.codeitbetter.co.uk/widgets/ellipsis/ Todo lo que necesita hacer es hacer referencia a la biblioteca y llamar a lo siguiente:

<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>

1

puede hacerlo mucho más fácil solo con css, por ejemplo: modo sass

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

y tienes puntos suspensivos;)


0

Al igual que @acSlater, no pude encontrar algo para lo que necesitaba, así que rodé el mío. Compartir en caso de que alguien más pueda usar:

Método:
ellipsisIfNecessary(mystring,maxlength);
Uso:
trimmedString = ellipsisIfNecessary(mystring,50);
Código y enlace de demostración: https://gist.github.com/cemerson/10368014

Dos anotaciones: a) Este código no verifica el tamaño real de un elemento HTML. Debe especificar una longitud determinada, que puede ser la funcionalidad requerida, pero en realidad es trivial. b) Simplemente agrega "..." al final de la cadena. Hay un signo de puntos suspensivos "..." que podría / debería usar.
BlaM

Hola @BlaM: el código en realidad comprueba la longitud contra el parámetro maxlength Al menos me está funcionando. Dicho esto, esta es solo mi humilde excepción para mi situación particular. Siéntase libre de usar cualquiera de las soluciones anteriores si esta no funciona bien para su situación.
Christopher D. Emerson

Sí, funciona con una "longitud", pero no con un "ancho" (tamaño de píxel).
BlaM

Idea interesante: siéntase libre de hacer una versión actualizada con soporte para eso. No necesito eso ahora, pero podría ser útil en el futuro.
Christopher D. Emerson

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: http://stackoverflow.com/questions/536814/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 lifeyour 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 lifeyour 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>
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.