varias truncar texto suspensivos puntos parte palabras mostrar lineas cortar con javascript jquery css

javascript - parte - truncar texto con puntos suspensivos



Cross browsers multilíneas texto desbordado con puntos suspensivos anexados dentro de un ancho y altura de div fijo? (20)

Demostración de Pure JS (sin jQuery y ''while'' loop)

Cuando busqué la solución del problema de la elipsis multilínea me sorprendió que no haya ninguna buena sin jQuery. También hay algunas soluciones basadas en el ciclo ''while'', pero creo que no son efectivas y peligrosas debido a la posibilidad de entrar en el ciclo infinito. Entonces escribí este código:

function ellipsizeTextBox(el) { if (el.scrollHeight <= el.offsetHeight) { return; } let wordArray = el.innerHTML.split('' ''); const wordsLength = wordArray.length; let activeWord; let activePhrase; let isEllipsed = false; for (let i = 0; i < wordsLength; i++) { if (el.scrollHeight > el.offsetHeight) { activeWord = wordArray.pop(); el.innerHTML = activePhrase = wordArray.join('' ''); } else { break; } } let charsArray = activeWord.split(''''); const charsLength = charsArray.length; for (let i = 0; i < charsLength; i++) { if (el.scrollHeight > el.offsetHeight) { charsArray.pop(); el.innerHTML = activePhrase + '' '' + charsArray.join('''') + ''...''; isEllipsed = true; } else { break; } } if (!isEllipsed) { activePhrase = el.innerHTML; let phraseArr = activePhrase.split(''''); phraseArr = phraseArr.slice(0, phraseArr.length - 3) el.innerHTML = phraseArr.join('''') + ''...''; } } let el = document.getElementById(''ellipsed''); ellipsizeTextBox(el);

Hice una imagen para esta pregunta, debería ser más fácil de entender.

He probado algunos plugins jquery aquí y allá, pero no puedo encontrar el que estoy buscando. ¿Alguna recomendacion? ideas?


Librerías de Javascript para "line clamping"

Tenga en cuenta que "pinzamiento de línea" también se conoce como "puntos suspensivos en el bloque de líneas múltiples" o "puntos suspensivos verticales".

github.com/BeSite/jQuery.dotdotdot

github.com/josephschmitt/Clamp.js

Aquí hay algunos más que aún no investigué:

Soluciones CSS para sujeción de línea

Hay algunas soluciones de CSS, pero la más simple usa -webkit-line-clamp que tiene poca compatibilidad con el navegador . Vea la demostración en vivo en jsfiddle.net/AdrienBe/jthu55v7/

Muchas personas hicieron grandes esfuerzos para que esto suceda usando solo CSS. Vea artículos y preguntas al respecto:

Lo que recomendaría

Mantenlo simple. A menos que tenga una gran cantidad de tiempo para dedicarse a esta función, busque la solución más simple y probada: CSS simple o una biblioteca de JavaScript bien probada.

Vaya por algo sofisticado / complejo / altamente personalizado y pagará el precio por esto en el futuro.

Lo que otros hacen

Tener un fundido de salida como Airbnb puede ser una buena solución. Probablemente es CSS básico junto con jQuery básico. En realidad, parece muy similar a esta solución en CSSTricks

Ah, y si buscas inspiraciones de diseño:


Aquí hay una forma pura de CSS para lograr esto: http://www.mobify.com/blog/multiline-ellipsis-in-pure-css/

Aquí hay un resumen:

<html> <head> <style> html, body, p { margin: 0; padding: 0; font-family: sans-serif;} .ellipsis { overflow: hidden; height: 200px; line-height: 25px; margin: 20px; border: 5px solid #AAA; } .ellipsis:before { content:""; float: left; width: 5px; height: 200px; } .ellipsis > *:first-child { float: right; width: 100%; margin-left: -5px; } .ellipsis:after { content: "/02026"; box-sizing: content-box; -webkit-box-sizing: content-box; -moz-box-sizing: content-box; float: right; position: relative; top: -25px; left: 100%; width: 3em; margin-left: -3em; padding-right: 5px; text-align: right; background: -webkit-gradient(linear, left top, right top, from(rgba(255, 255, 255, 0)), to(white), color-stop(50%, white)); background: -moz-linear-gradient(to right, rgba(255, 255, 255, 0), white 50%, white); background: -o-linear-gradient(to right, rgba(255, 255, 255, 0), white 50%, white); background: -ms-linear-gradient(to right, rgba(255, 255, 255, 0), white 50%, white); background: linear-gradient(to right, rgba(255, 255, 255, 0), white 50%, white); } </style> </head> <body> <div class="ellipsis"> <div> <p>Call me Ishmael.....</p> </div> </div> </body> </html>


Aquí hay una solución de JavaScript vainilla que puedes usar en un apuro:

// @param 1 = element containing text to truncate // @param 2 = the maximum number of lines to show function limitLines(el, nLines) { var nHeight, el2 = el.cloneNode(true); // Create clone to determine line height el2.style.position = ''absolute''; el2.style.top = ''0''; el2.style.width = ''10%''; el2.style.overflow = ''hidden''; el2.style.visibility = ''hidden''; el2.style.whiteSpace = ''nowrap''; el.parentNode.appendChild(el2); nHeight = (el2.clientHeight+2)*nLines; // Add 2 pixels of slack // Clean up el.parentNode.removeChild(el2); el2 = null; // Truncate until desired nLines reached if (el.clientHeight > nHeight) { var i = 0, imax = nLines * 35; while (el.clientHeight > nHeight) { el.innerHTML = el.textContent.slice(0, -2) + ''&hellip;''; ++i; // Prevent infinite loop in "print" media query caused by // Bootstrap 3 CSS: a[href]:after { content:" (" attr(href) ")"; } if (i===imax) break; } } } limitLines(document.getElementById(''target''), 7);

#test { width: 320px; font-size: 18px; }

<div id="test"> <p>Paragraph 1</p> <p id="target">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> <p>Paragraph 3</p> </div>

Puedes jugar con él en el códepen a continuación. Intente cambiar el tamaño de la fuente en el panel de CSS y realice una edición menor en el panel de HTML (por ejemplo, agregue un espacio extra en alguna parte) para actualizar los resultados. Independientemente del tamaño de la fuente, el párrafo del medio siempre se debe truncar al número de líneas en el segundo parámetro pasado a limitLines ().

Codepen: http://codepen.io/thdoan/pen/BoXbEK


Aquí hice otra biblioteca con algoritmo más rápido. Por favor, compruebe:

https://github.com/i-ahmed-biz/fast-ellipsis

Para instalar usando bower:

bower install fast-ellipsis

Para instalar usando npm:

bower install fast-ellipsis

¡Espero que lo disfrutes!


Con este código no hay necesidad de un div adicional envoltorio si el elemento tiene su altura limitada por un estilo de altura máxima.

// Shorten texts in overflowed paragraphs to emulate Operas text-overflow: -o-ellipsis-lastline $(''.ellipsis-lastline'').each(function(i, e) { var $e = $(e), original_content = $e.text(); while (e.scrollHeight > e.clientHeight) $e.text($e.text().replace(//W*/w+/W*$/, ''…'')); $e.attr(''data-original-content'', original_content); });

También guarda el texto original en un atributo de datos que se puede mostrar usando solo estilos, ej. el ratón por encima:

.ellipsis-lastline { max-height: 5em; } .ellipsis-lastline:before { content: attr(data-original-content); position: absolute; display: none; } .ellipsis-lastline:hover:before { display: block; }


EDITAR: Encontré Shave que es un plugin de JS que hace muy bien el truncamiento de texto de múltiples líneas basado en una altura máxima dada. Utiliza la búsqueda binaria para encontrar el punto de ruptura óptimo. Definitivamente vale la pena investigar.

RESPUESTA ORIGINAL:

Tuve que encontrar una solución vanisa de JS para este problema. En el caso en que trabajé, tuve que ajustar un largo nombre de producto en ancho limitado y en dos líneas; truncado por elipsis si es necesario.

Utilicé respuestas de varias publicaciones de SO para cocinar algo que se ajustaba a mis necesidades. La estrategia es la siguiente:

  1. Calcule el ancho promedio de caracteres de la variante de fuente para el tamaño de fuente deseado.
  2. Calcule el ancho del contenedor
  3. Calcule el número de caracteres que caben en una línea en el contenedor
  4. Calcule el número de caracteres para truncar la cadena en función de la cantidad de caracteres que caben en una línea y el número de líneas que el texto debe envolver.
  5. Truncar el texto de entrada en función del cálculo anterior (factorizando los caracteres adicionales añadidos mediante puntos suspensivos) y anexar "..." al final

Muestra de código:

/** * Helper to get the average width of a character in px * NOTE: Ensure this is used only AFTER font files are loaded (after page load) * @param {DOM element} parentElement * @param {string} fontSize */ function getAverageCharacterWidth(parentElement, fontSize) { var textSample = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890!@#$%^&*()"; parentElement = parentElement || document.body; fontSize = fontSize || "1rem"; var div = document.createElement(''div''); div.style.width = "auto"; div.style.height = "auto"; div.style.fontSize = fontSize; div.style.whiteSpace = "nowrap"; div.style.position = "absolute"; div.innerHTML = textSample; parentElement.appendChild(div); var pixels = Math.ceil((div.clientWidth + 1) / textSample.length); parentElement.removeChild(div); return pixels; } /** * Helper to truncate text to fit into a given width over a specified number of lines * @param {string} text Text to truncate * @param {string} oneChar Average width of one character in px * @param {number} pxWidth Width of the container (adjusted for padding) * @param {number} lineCount Number of lines to span over * @param {number} pad Adjust this to ensure optimum fit in containers. Use a negative value to Increase length of truncation, positive values to decrease it. */ function truncateTextForDisplay(text, oneChar, pxWidth, lineCount, pad) { var ellipsisPadding = isNaN(pad) ? 0 : pad; var charsPerLine = Math.floor(pxWidth / oneChar); var allowedCount = (charsPerLine * (lineCount)) - ellipsisPadding; return text.substr(0, allowedCount) + "..."; } //SAMPLE USAGE: var rawContainer = document.getElementById("raw"); var clipContainer1 = document.getElementById("clip-container-1"); var clipContainer2 = document.getElementById("clip-container-2"); //Get the text to be truncated var text=rawContainer.innerHTML; //Find the average width of a character //Note: Ideally, call getAverageCharacterWidth only once and reuse the value for the same font and font size as this is an expensive DOM operation var oneChar = getAverageCharacterWidth(); //Get the container width var pxWidth = clipContainer1.clientWidth; //Number of lines to span over var lineCount = 2; //Truncate without padding clipContainer1.innerHTML = truncateTextForDisplay(text, oneChar, pxWidth, lineCount); //Truncate with negative padding value to adjust for particular font and font size clipContainer2.innerHTML = truncateTextForDisplay(text, oneChar, pxWidth, lineCount,-10);

.container{ display: inline-block; width: 200px; overflow: hidden; height: auto; border: 1px dotted black; padding: 10px; }

<h4>Untruncated</h4> <div id="raw" class="container"> This is super long text which needs to be clipped to the correct length with ellipsis spanning over two lines </div> <h4>Truncated</h4> <div id="clip-container-1" class="container"> </div> <h4>Truncated with Padding Tweak</h4> <div id="clip-container-2" class="container"> </div>

PD:

  1. Si el truncamiento debe estar en una sola línea, el método de CSS puro para usar el desbordamiento de texto: elipsis es más nítido
  2. Las fuentes que no tienen un ancho fijo pueden causar que el truncamiento ocurra demasiado temprano o demasiado tarde (ya que los caracteres diferentes tienen diferentes anchos). Usar el parámetro pad ayuda a mitigar esto en algunos casos, pero no será infalible :)
  3. Agregará enlaces y referencias a las publicaciones originales después de que recupere mi computadora portátil (necesito un historial)

PPS: Acabo de darme cuenta de que esto es muy similar al enfoque sugerido por @DanMan y @ st.never. Consulte los fragmentos de código para ver un ejemplo de implementación.


El plugin dotdotdot jQuery mencionado funciona bien con angular:

(function (angular) { angular.module(''app'') .directive(''appEllipsis'', [ "$log", "$timeout", function ($log, $timeout) { return { restrict: ''A'', scope: false, link: function (scope, element, attrs) { // let the angular data binding run first $timeout(function() { element.dotdotdot({ watch: "window" }); }); } } } ]); })(window.angular);

El marcado correspondiente sería:

<p app-ellipsis>{{ selectedItem.Description }}</p>


En mi caso, no podía ponerme a trabajar en ninguna de las funciones mencionadas anteriormente y también necesitaba decirle a la función cuántas líneas mostrar independientemente del tamaño de la fuente o del tamaño del contenedor.

Canvas.measureText mi solución en el uso del método Canvas.measureText (que es una función de HTML5 ) tal como lo explica Domi , por lo que no es completamente entre navegadores.

Puedes ver cómo funciona en este violín .

Este es el código:

var processTexts = function processTexts($dom) { var canvas = processTexts .canvas || (processTexts .canvas = document.createElement("canvas")); $dom.find(''.block-with-ellipsis'').each(function (idx, ctrl) { var currentLineAdded = false; var $this = $(ctrl); var font = $this.css(''font-family'').split(",")[0]; //This worked for me so far, but it is not always so easy. var fontWeight = $(this).css(''font-weight''); var fontSize = $(this).css(''font-size''); var fullFont = fontWeight + " " + fontSize + " " + font; // re-use canvas object for better performance var context = canvas.getContext("2d"); context.font = fullFont; var widthOfContainer = $this.width(); var text = $.trim(ctrl.innerHTML); var words = text.split(" "); var lines = []; //Number of lines to span over, this could be calculated/obtained some other way. var lineCount = $this.data(''line-count''); var currentLine = words[0]; var processing = ""; var isProcessing = true; var metrics = context.measureText(text); var processingWidth = metrics.width; if (processingWidth > widthOfContainer) { for (var i = 1; i < words.length && isProcessing; i++) { currentLineAdded = false; processing = currentLine + " " + words[i]; metrics = context.measureText(processing); processingWidth = metrics.width; if (processingWidth <= widthOfContainer) { currentLine = processing; } else { if (lines.length < lineCount - 1) { lines.push(currentLine); currentLine = words[i]; currentLineAdded = true; } else { processing = currentLine + "..."; metrics = context.measureText(processing); processingWidth = metrics.width; if (processingWidth <= widthOfContainer) { currentLine = processing; } else { currentLine = currentLine.slice(0, -3) + "..."; } lines.push(currentLine); isProcessing = false; currentLineAdded = true; } } } if (!currentLineAdded) lines.push(currentLine); ctrl.innerHTML = lines.join(" "); } }); }; (function () { $(document).ready(function () { processTexts($(document)); }); })();

Y el HTML para usar sería así:

<div class="block-with-ellipsis" data-line-count="2"> VERY LONG TEXT THAT I WANT TO BREAK IN LINES. VERY LONG TEXT THAT I WANT TO BREAK IN LINES. </div>

El código para obtener la familia de fuentes es bastante simple, y en mi caso funciona, pero para escenarios más complejos puede que necesite usar algo en esta línea .

Además, en mi caso, le estoy diciendo a la función cuántas líneas usar, pero podrías calcular cuántas líneas mostrar de acuerdo con el tamaño del contenedor y la fuente.


Func muy simple servirá.

Directiva:

$scope.truncateAlbumName = function (name) { if (name.length > 36) { return name.slice(0, 34) + ".."; } else { return name; } };

Ver:

<#p>{{truncateAlbumName(album.name)}}<#/p>


No es una respuesta exacta a la pregunta, pero me encontré con esta página cuando trato de hacer algo muy similar, pero con ganas de agregar un enlace para "ver más" en lugar de solo una elipsis simple. Esta es una función jQuery que agregará un enlace "más" al texto que está desbordando un contenedor. Personalmente estoy usando esto con Bootstrap, pero por supuesto funcionará sin él.

Para usar, coloque su texto en un contenedor de la siguiente manera:

<div class="more-less"> <div class="more-block"> <p>The long text goes in here</p> </div> </div>

Cuando se agrega la siguiente función jQuery, cualquiera de los divs que son más grandes que el valor de valor de ajuste se truncarán y se agregará un enlace "Más".

$(function(){ var adjustheight = 60; var moreText = ''+ More''; var lessText = ''- Less''; $(".more-less .more-block").each(function(){ if ($(this).height() > adjustheight){ $(this).css(''height'', adjustheight).css(''overflow'', ''hidden''); $(this).parent(".more-less").append (''<a style="cursor:pointer" class="adjust">'' + moreText + ''</a>''); } }); $(".adjust").click(function() { if ($(this).prev().css(''overflow'') == ''hidden'') { $(this).prev().css(''height'', ''auto'').css(''overflow'', ''visible''); $(this).text(lessText); } else { $(this).prev().css(''height'', adjustheight).css(''overflow'', ''hidden''); $(this).text(moreText); } }); });

Basado en esto, pero actualizado: http://shakenandstirredweb.com/240/jquery-moreless-text


No existe tal característica en HTML, y esto es muy frustrante.

He desarrollado una library para lidiar con esto.

  • Desbordamiento de texto multilínea: puntos suspensivos
  • Texto de líneas múltiples con tecnologías que no lo admiten: SVG, Canvas por ejemplo
  • Tenga exactamente los mismos saltos de línea en su texto SVG, en su representación HTML y en su exportación PDF, por ejemplo

Echa un vistazo a mi sitio para ver la captura de pantalla, el tutorial y el enlace de descarga.


Para expandir la solución de @ DanMan: en el caso de que se utilicen fuentes de ancho variable, podría usar un ancho de fuente promedio. Esto tiene dos problemas: 1) un texto con demasiados W se desbordará y 2) un texto con demasiados I sería truncado antes.

O podría tomar el peor de los casos y usar el ancho de la letra "W" (que creo que es el más ancho). Esto elimina el problema 1 anterior pero intensifica el problema 2.

Un enfoque diferente podría ser: dejar overflow: clip en el div y agregar una sección de puntos suspensivos (tal vez otra div o imagen) con float: right; position: relative; bottom: 0px; float: right; position: relative; bottom: 0px; (no probado). El truco es hacer que la imagen aparezca sobre el final del texto.

También podría mostrar la imagen solo cuando sepa que se desbordará (por ejemplo, después de unos 100 caracteres)


Probablemente no pueda hacerlo (¿actualmente?) Sin una fuente de ancho fijo como Courier. Con una fuente de ancho fijo, todas las letras ocupan el mismo espacio horizontal, por lo que probablemente puedas contar las letras y multiplicar el resultado con el tamaño de fuente actual en ems o exs. Entonces solo tendrías que probar cuántas letras encajan en una línea y luego descomponerla.

Alternativamente, para tipos de letra no fijos, puede crear una asignación para todos los caracteres posibles (como i = 2px, m = 5px) y luego hacer los cálculos. Sin embargo, un montón de trabajo feo.



Quizás bastante tarde pero usando SCSS puedes declarar una función como:

@mixin clamp-text($lines, $line-height) { overflow: hidden; text-overflow: ellipsis; display: -webkit-box; -webkit-box-orient: vertical; -webkit-line-clamp: $lines; line-height: $line-height; max-height: unquote(''#{$line-height*$lines}em''); @-moz-document url-prefix() { position: relative; height: unquote(''#{$line-height*$lines}em''); &::after { content: ''''; text-align: right; position: absolute; bottom: 0; right: 0; width: 30%; height: unquote(''#{$line-height}em''); background: linear-gradient( to right, rgba(255, 255, 255, 0), rgba(255, 255, 255, 1) 50% ); } } }

Y úsalo como:

.foo { @include clamp-text(1, 1.4); }

Lo cual truncará el texto a una línea y sabiendo que es 1.4 su altura de línea. La salida esperada es que Chrome se renderice con ... al final y FF con un cierto fade al final

Firefox

Cromo


Solución Pure JS basada en la solución de bažmegakapa, y algo de limpieza para tener en cuenta a las personas que intentan dar una altura / altura máxima menor que la línea del elementoAltura:

var truncationEl = document.getElementById(''truncation-test''); function calculateTruncation(el) { var text; while(el.clientHeight < el.scrollHeight) { text = el.innerHTML.trim(); if(text.split('' '').length <= 1) { break; } el.innerHTML = text.replace(//W*/s(/S)*$/, ''...''); } } calculateTruncation(truncationEl);


Tengo una solución que funciona bien, pero en lugar de una elipsis usa un gradiente. Las ventajas son que no tiene que hacer ningún cálculo de JavaScript y funciona para contenedores de ancho variable, incluidas las celdas de la tabla. Utiliza un par de divs adicionales, pero es muy fácil de implementar.

http://salzerdesign.com/blog/?p=453

Editar: Lo siento, no sabía que el enlace no era suficiente. La solución es colocar un div alrededor del texto y darle estilo al div para controlar el desbordamiento. Dentro del div, coloca otro div con un degradado "fade" que se puede hacer usando CSS o una imagen (para el viejo IE). El degradado va del transparente al color de fondo de la celda de la tabla y es un poco más ancho que una elipsis. Si el texto es largo y se desborda, pasa por debajo del divisor "fade" y se ve como "desvanecido". Si el texto es corto, el fundido es invisible, por lo que no hay problema. Los dos contenedores se pueden ajustar para que se muestren una o varias líneas estableciendo la altura del contenedor como un múltiplo de la altura de la línea de texto. El div "fade" se puede posicionar para cubrir solo la última línea.


no estoy seguro de si esto es lo que está buscando, usa min-height en lugar de height.

<div id="content" style="min-height:10px;width:190px;background:lightblue;"> <?php function truncate($text,$numb) { // source: www.kigoobe.com, please keep this if you are using the function $text = html_entity_decode($text, ENT_QUOTES); if (strlen($text) > $numb) { $text = substr($text, 0, $numb); $etc = "..."; $text = $text.$etc; } $text = htmlentities($text, ENT_QUOTES); return $text; } echo truncate("this is a multi-lines text block, some lines inside the div, while some outside", 63); ?> </div>


Solo una idea básica rápida.

Estaba probando con el siguiente marcado:

<div id="fos"> <p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Proin nisi ligula, dapibus a volutpat sit amet, mattis et dui. Nunc porttitor accumsan orci id luctus. Phasellus ipsum metus, tincidunt non rhoncus id, dictum a lectus. Nam sed ipsum a lacus sodales eleifend. Vestibulum lorem felis, rhoncus elementum vestibulum eget, dictum ut velit. Nullam venenatis, elit in suscipit imperdiet, orci purus posuere mauris, quis adipiscing ipsum urna ac quam.</p> </div>

Y CSS:

#fos { width: 300px; height: 190px; overflow: hidden; } #fos p { padding: 10px; margin: 0; }

La aplicación de este jQuery logrará el resultado deseado:

var $p = $(''#fos p''); var divh = $(''#fos'').height(); while ($p.outerHeight() > divh) { $p.text(function (index, text) { return text.replace(//W*/s(/S)*$/, ''...''); }); }

Intenta repetidamente eliminar la última palabra del texto hasta que alcanza el tamaño deseado. Debido al desbordamiento: oculto; el proceso permanece invisible e incluso con JS desactivado, el resultado permanece ''visualmente correcto'' (sin el "..." por supuesto).

Si combina esto con un truncamiento razonable en el lado del servidor (eso deja solo una pequeña sobrecarga), se ejecutará más rápido :).

De nuevo, esta no es una solución completa, solo una idea.

ACTUALIZACIÓN: se agregó una demostración jsFiddle .