Pregunta

Necesito implementar puntos suspensivos ( " ... " ) en el medio de un texto dentro de un elemento redimensionable. Aquí es lo que podría parecer. Entonces,

"Lorem ipsum dolor sit amet. Ut ornare dignissim ligula sed commodo."

se convierte

"Lorem ipsum dolor sit amet ... commodo."

Cuando el elemento se extiende al ancho del texto, quiero que desaparezcan los puntos suspensivos. ¿Cómo se puede hacer esto?

¿Fue útil?

Solución

En el HTML, coloque el valor completo en un atributo personalizado data- * como

<span data-original="your string here"></span>

Luego asigne oyentes de eventos load y resize a una función JavaScript que leerá el atributo de datos original y lo colocará en el innerHTML de su etiqueta de tramo. Aquí hay un ejemplo de la función de puntos suspensivos:

function start_and_end(str) {
  if (str.length > 35) {
    return str.substr(0, 20) + '...' + str.substr(str.length-10, str.length);
  }
  return str;
}

Ajusta los valores, o si es posible, hazlos dinámicos, si es necesario para diferentes objetos. Si tiene usuarios de diferentes navegadores, puede robar un ancho de referencia de un texto con la misma fuente y tamaño en otra parte de su dom. Luego interpola a una cantidad apropiada de caracteres para usar.

Un consejo también es tener una etiqueta abbr en el mensaje ... o who para que el usuario pueda obtener información sobre herramientas con la cadena completa.

<abbr title="simple tool tip">something</abbr>

Otros consejos

Me gustaría proponer mi ejemplo de resolución de este problema.

La idea principal es dividir el texto en dos partes pares (o la primera es más grande, si la longitud es impar), una de las cuales tiene puntos suspensivos al final y otra alineada a la derecha con text-overflow: clip .

Entonces, todo lo que necesita hacer con js, si desea que sea automático / universal, es dividir la cadena y establecer los atributos.

Sin embargo, tiene algunas desventajas.

  1. No es agradable envolver con palabras o incluso letras ( text-overflow: '' solo funciona en FF en este momento)
  2. Si la división ocurre entre palabras, el espacio debe estar en la primera parte. De lo contrario, se colapsará.
  3. El final de la cadena no debe tener ningún signo de exclamación, debido a la dirección : rtl : se moverán a la izquierda de la cadena. Creo que es posible solucionar esto poniendo la parte correcta de la palabra en la etiqueta y el signo de exclamación en el pseudo-elemento :: after . Pero aún no lo he hecho funcionar correctamente.

Pero, con todo esto, me parece realmente genial, especialmente cuando arrastra el borde del navegador, lo que puede hacer en la página jsfiddle fácilmente: https://jsfiddle.net/extempl/93ymy3oL/ . O simplemente ejecute el fragmento con el ancho máximo fijo a continuación.

Gif bajo el spoiler:

  

 Gif

body {
  max-width: 400px;
}

span::before, span::after {
  display: inline-block;
  max-width: 50%;
  overflow: hidden;
  white-space: pre;
}

span::before {
  content: attr(data-content-start);
  text-overflow: ellipsis;
}

span::after {
  content: attr(data-content-end);
  text-overflow: '';
  direction: rtl;
}
<span data-content-start="Look deep into nature, and then you " 
      data-content-end=  "will understand everything better"></span>

<br>
<span data-content-start="https://www.google.com.ua/images/branding/g" 
      data-content-end=  "ooglelogo/2x/googlelogo_color_272x92dp.png"></span>

Entonces, a mi colega se le ocurrió una solución que no utiliza elementos dom adicionales. Verificamos si el div se desborda y agregamos un atributo de datos de los últimos n caracteres. El resto se hace en CSS.

Aquí hay algo de HTML:

<div class="box">
    <div class="ellipsis" data-tail="some">This is my text it is awesome</div>
</div>
<div class="box">
    <div class="ellipsis">This is my text</div>
</div>

Y el css:

.box {
    width: 200px;
}

.ellipsis:before {
    float: right;
    content: attr(data-tail);
}

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

Aquí está el jsfiddle obligatorio para esto: http://jsfiddle.net/r96vB/1/

La siguiente función Javascript hará un truncamiento medio, como OS X:

function smartTrim(string, maxLength) {
    if (!string) return string;
    if (maxLength < 1) return string;
    if (string.length <= maxLength) return string;
    if (maxLength == 1) return string.substring(0,1) + '...';

    var midpoint = Math.ceil(string.length / 2);
    var toremove = string.length - maxLength;
    var lstrip = Math.ceil(toremove/2);
    var rstrip = toremove - lstrip;
    return string.substring(0, midpoint-lstrip) + '...' 
    + string.substring(midpoint+rstrip);
}       

Reemplazará caracteres en el medio con puntos suspensivos. Mis pruebas unitarias muestran:

var s = '1234567890';
assertEquals(smartTrim(s, -1), '1234567890');
assertEquals(smartTrim(s, 0), '1234567890');
assertEquals(smartTrim(s, 1), '1...');
assertEquals(smartTrim(s, 2), '1...0');
assertEquals(smartTrim(s, 3), '1...90');
assertEquals(smartTrim(s, 4), '12...90');
assertEquals(smartTrim(s, 5), '12...890');
assertEquals(smartTrim(s, 6), '123...890');
assertEquals(smartTrim(s, 7), '123...7890');
assertEquals(smartTrim(s, 8), '1234...7890');
assertEquals(smartTrim(s, 9), '1234...67890');
assertEquals(smartTrim(s, 10), '1234567890');
assertEquals(smartTrim(s, 11), '1234567890');

No puedes hacer eso con CSS. El problema es que se supone que HTML y CSS funcionan en una variedad de navegadores y fuentes y es casi imposible calcular el ancho de una cadena de manera consistente. Esta es una idea que podría ayudarlo. Sin embargo, deberá hacerlo varias veces, hasta que encuentre la cadena con el ancho adecuado.

Esto puede ser un poco tarde en el juego, pero estaba buscando una solución para esto, y un colega sugirió una muy elegante, que compartiré. Requiere algo de JS, pero no mucho.

Imagine que tiene un div del tamaño en el que necesita poner su etiqueta:

<div style="width: 200px; overflow: hidden"></div>

Ahora, tiene una función que tomará dos parámetros: una cadena con la etiqueta y un elemento DOM (este div ) para encajarlo en:

function setEllipsisLabel(div, label) 

Lo primero que debe hacer es crear un span con esta etiqueta y colocarlo en el div :

var span = document.createElement('span');
span.appendChild(document.createTextNode(label));
span.style.textOverflow = 'ellipsis';
span.style.display = 'inline-block';
div.appendChild(span);

Establecemos la propiedad text-overflow en "puntos suspensivos" de modo que a medida que el texto se corta, un agradable "..." se agrega al final para ilustrar esto. También configuramos display para ser " inline-block " para que estos elementos tengan dimensiones de píxeles reales que podamos manipular más adelante. Hasta ahora, nada que no podríamos haber hecho con CSS puro.

Pero queremos los puntos suspensivos en el medio. Primero, deberíamos averiguar si lo necesitamos ... Esto se puede hacer comparando div.clientWidth con span.clientWidth : los puntos suspensivos solo son necesarios si el < code> span es más ancho que el div .

Si necesitamos puntos suspensivos, comencemos diciendo que queremos que se muestre un número fijo de caracteres al final de la palabra, digamos 10. Entonces, creemos un espacio que contenga solo los últimos 10 caracteres de la etiqueta y peguemos en el div:

var endSpan = document.createElement('span');
endSpan.style.display = 'inline-block';
endspan.appendChild(document.createTextNode(label.substring(label.length - 10)));
div.appendChild(endSpan);

Ahora, anulemos el ancho del span original para acomodar el nuevo:

span.style.width = (div.clientWidth - endSpan.clientWidth) + 'px';

Como resultado de esto, ahora tenemos una estructura DOM que se parece a esto:

<div style="width: 200px; overflow: hidden">
   <span style="display: inline-block; text-overflow: ellipsis; width: 100px">
      A really long label is shown in this span
   </span>
   <span style="display: inline-block"> this span</span>
</div>

Debido a que el primer span tiene text-overflow establecido en '' puntos suspensivos '', mostrará '' ... '' al final, seguido de los 10 caracteres del segundo tramo, lo que resulta en puntos suspensivos que se muestran aproximadamente en el medio del div .

Tampoco es necesario codificar la longitud de 10 caracteres para endSpan: esto puede aproximarse calculando la relación del ancho inicial del span con el del div , restando la proporción adecuada de la longitud de la etiqueta y dividiendo por dos.

Después de investigar un poco sobre las cajas flexibles, encontré esta solución CSS pura que creo que es bastante genial.

<div style="width:100%;border:1px solid green;display:inline-flex;flex-wrap:nowrap;">
   <div style="flex: 0 1 content;text-overflow: ellipsis;overflow:hidden;white-space:nowrap;"> Her comes very very very very very very very very very very very very very very very very very very very long </div>
   <div style="flex: 1 0 content;white-space:nowrap;"> &nbsp;but flexible line</div>
</div>

Aquí está el bit más corto que pude encontrar que reemplaza 3 caracteres en el medio con ...

function shorten(s, max) {
  return s.length > max ? s.substring(0, (max / 2) - 1) + '...' + s.substring(s.length - (max / 2) + 2, s.length) : s
}

Esta solución es una mezcla de las soluciones anteriores y pone la última palabra completa al final del texto abreviado. Sin embargo, en caso de que la última palabra sea más larga, un tercio del espacio disponible también se acorta desde la izquierda. Si se encuentra un guión (" - "), córtelo allí, si no, córtelo de todos modos.

function truncate(text, textLimit) {
    if (!text) return text;
    if (textLimit < 1) return string;
    if (text.length < textLimit) return text;
    if (textLimit === 1) return text.substring(0,1) + '...';
    /* extract the last word */
    var lastPart = text.slice( string.lastIndexOf(' ')+1 );
    /* if last word is longer then a third of the max available space
       cut it from the left */
    var lastPartLimit = Math.ceil(textLimit / 3);
    if(lastPart.length > lastPartLimit) {
        var truncatedLastPart = lastPart;
        /* Try to find a dash and cut the last word there */
        var lastDashPart = text.slice( text.lastIndexOf('-')+1 );
        if(lastDashPart.length < lastPartLimit){
            truncatedLastPart = lastDashPart;
        }
        /* If the last part is still to long or not available cut it anyway */
        if(truncatedLastPart.length > lastPartLimit) {
            var lastIndex = lastPart.length - lastPartLimit;
            truncatedLastPart = lastPart.substring( lastIndex );
        }
        lastPart = truncatedLastPart;
    }
    var dots = '... ';
    var firsPartLength = textLimit - lastPart.length - dots.length;
    return text.substring(0, firstPartLength) + dots + lastPart;
}

console.log( truncate("New York City", 10) ); // Ne... City (max of 10 characters)
console.log( truncate("New York Kindergarden", 14) ); // Ne...ergarden (max of 14 characters, last word gets cut from the left by a third)
console.log( truncate("New York Kinder-garden", 14) ); // Ne...garden (max of 14 characters, last word gets cut by the dash from the left)

Acabo de crear una función que puede recortar en el medio, cerca de Fin y Fin, pero aún no se ha probado porque finalmente la necesitaba en el lado del servidor

//position acceptable values : middle, end, closeEnd
function AddElipsis(input, maxChars, position) {
    if (typeof input === 'undefined') {
        return "";
    }
    else if (input.length <= maxChars) {
        return input;
    }
    else {
        if (position == 'middle') {
            var midPos = Math.floor(maxChars / 2) - 2;
            return input.substr(0, midPos) + '...' + input.substr(input.length - midPos, input.length);
        }
        else if (position == 'closeEnd') {
            var firstPart = Math.floor(maxChars * 0.80) - 2;
            var endPart = Math.floor(maxChars * 0.20) - 2;
            return input.substr(0, firstPart) + '...' + input.substr(input.length - endPart, input.length);
        }
        else {
            return input.substr(0, maxChars - 3) + '...';
        }
    }
}

Otra puñalada:

function truncate( str, max, sep ) {
    max = max || 10;
    var len = str.length;
    if(len > max){
        sep = sep || "...";
        var seplen = sep.length;
        if(seplen > max) { return str.substr(len - max) }

        var n = -0.5 * (max - len - seplen);
        var center = len/2;
        return str.substr(0, center - n) + sep + str.substr(len - center + n);
    }
    return str;
}

console.log( truncate("123456789abcde") ); // 123...bcde (using built-in defaults) 
console.log( truncate("123456789abcde", 8) ); // 12...cde (max of 8 characters) 
console.log( truncate("123456789abcde", 12, "_") ); // 12345_9abcde (customize the separator) 

Esto le dará un poco más de control sobre la posición de los puntos suspensivos y el texto del marcador de posición:

function ellipsis(str, maxLength, ellipsisLocationPercentage,placeholder) {
    /*
    ARGUMENTS:
    str - the string you want to maninpulate
    maxLength -  max number of characters allowed in return string
    ellipsisLocationPercentage (optional) - How far (percentage wise) into the return string you want the ellipses to be placed
        Examples:
        .85 : This is a very long string. This is a very long string. This is a very long string. This is a ver[...]very long string.
        .25 : This is a very long string. [...]g. This is a very long string. This is a very long string. This is a very long string.
    placeholder (optional) - this will be used to replace the removed substring. Suggestions : '...', '[..]', '[ ... ]', etc....
    */
    if(ellipsisLocationPercentage == null || isNaN(ellipsisLocationPercentage) || ellipsisLocationPercentage >= 1 || ellipsisLocationPercentage <= 0){
        //we've got null or bad data.. default to something fun, like 85% (that's fun, right??)
        ellipsisLocationPercentage = .85;
    }
    if(placeholder == null || placeholder ==""){
        placeholder = "[...]";
    }

    if (str.length > (maxLength-placeholder.length)) {
        //get the end of the string
        var beginning = str.substr(0, (maxLength - placeholder.length)*ellipsisLocationPercentage );
        var end = str.substr(str.length-(maxLength - placeholder.length) * (1-ellipsisLocationPercentage));
        return beginning + placeholder + end;
    }
    return str;
}

Puede llamar a esta función llamando:

ellipsis("This is a very long string. Be Scared!!!!", 8);//uses default values
ellipsis("This is a very long string. Be Scared!!!!", 8,.5);//puts ellipsis at half way point
ellipsis("This is a very long string. Be Scared!!!!", 8,.75,'<..>');//puts ellipsis at 75% of the way into the string and uses '<..>' as the placeholder

Para hacer un corte limpio y tener una palabra completa al final del texto abreviado, utilicé la siguiente función.

function prepareText(text){
  var returnString = text;
  var textLimit = 35;
  if(text.length > textLimit){
    var lastWord = text.slice( text.lastIndexOf(' ')+1 );
    var indexFromEnd = lastWord.length;
    var ellipsis = '... ';

    returnString = text.slice(0, textLimit - indexFromEnd - ellipsis.length);
    returnString = returnString + ellipsis + lastWord;
  }
  return returnString;
}

$('#ex1Modified').html( prepareText( $('#ex1').html() ) );

$('#ex2Modified').html( prepareText( $('#ex2').html() ) );

$('#ex3Modified').html( prepareText( $('#ex3').html() ) );
body{color:#777; font-family: sans-serif;}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>

<h2>Shortened Quotes from Albert Einstein</h2>

<div id="ex1">"The true sign of intelligence is not knowledge but imagination."</div>
<div id="ex1Modified"></div>
<br>
<div id="ex2">"Look deep into nature, and then you will understand everything better."</div>
<div id="ex2Modified"></div>
<br>
<div id="ex3">"You can't blame gravity for falling in love."</div>
<div id="ex3Modified"></div>

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top