web-dev-qa-db-fra.com

Ellipsis au milieu d'un texte (style Mac)

J'ai besoin d'implémenter Ellipsis ("...") au milieu d'un texte dans un élément redimensionnable. Ici est ce que cela pourrait ressembler. Alors,

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

devient

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

Lorsque l'élément est étendu à la largeur du texte, je veux que les ellipses disparaissent. Comment cela peut-il être fait?

38
user102465

Dans le code HTML, placez la valeur complète dans un attribut data- * personnalisé, comme

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

Assignez ensuite les écouteurs d'événements load et resize à une fonction JavaScript qui lira l'attribut de données d'origine et le placera dans la innerHTML de votre balise span. Voici un exemple de la fonction Ellipsis:

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

Ajustez les valeurs ou, si possible, rendez-les dynamiques, si nécessaire pour différents objets. Si vous avez des utilisateurs de différents navigateurs, vous pouvez voler la largeur de référence d'un texte avec la même police et la même taille ailleurs dans votre dom. Ensuite, interpolez à une quantité appropriée de caractères à utiliser.

Une astuce consiste également à avoir un abbr-tag sur le message ... ou à qui faire en sorte que l'utilisateur puisse obtenir une info-bulle avec la chaîne complète.

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

Je voudrais proposer mon exemple de résolution de ce problème.

L'idée principale est de scinder le texte en deux parties paires (ou la première est plus grande si la longueur est impair), l'une d'elles ayant des ellipsis à la fin et l'autre alignée à droite avec text-overflow: clip.

Donc, tout ce que vous avez à faire avec js, si vous voulez le rendre automatique/universel - est de scinder la chaîne et de définir les attributs.

Il a cependant quelques inconvénients. 

  1. Pas d'habillage sympa avec des mots, ni même des lettres (text-overflow: '' fonctionne seulement en FF pour le moment)
  2. Si la division se produit entre des mots, l’espace doit figurer dans la première partie. Sinon, il sera réduit.
  3. La fin de la chaîne ne devrait pas avoir de points d'exclamation, à cause de direction: rtl - ils seront déplacés vers la gauche de la chaîne. Je pense qu'il est possible de résoudre ce problème en mettant une partie droite du mot dans la balise et un point d'exclamation dans le pseudo-élément ::after. Mais je ne l'ai pas encore fait fonctionner correctement.

Mais, avec tout cela, cela me semble vraiment cool, surtout lorsque vous faites glisser la bordure du navigateur, ce que vous pouvez faire facilement sur la page jsfiddle: https://jsfiddle.net/extempl/93ymy3oL/ . Ou exécutez simplement l'extrait de code avec la largeur maximale fixe ci-dessous.

Gif sous le 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>

19
extempl

Mon collègue a donc proposé une solution qui n’utilise aucun élément dom supplémentaire. Nous vérifions si la div déborde et ajoutons un attribut de données des n derniers caractères. Le reste est fait en css.

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

Et le css:

.box {
    width: 200px;
}

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

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

Voici le jsfiddle obligatoire pour cela: http://jsfiddle.net/r96vB/1/

9
Dan Perry

La fonction Javascript suivante fera une troncature moyenne, comme 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);
}       

Il remplacera les personnages au milieu par Ellipsis. Mes tests unitaires montrent:

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');
6
johnvey

C'est peut-être un peu tard dans le jeu, mais je cherchais une solution, et un collègue en a suggéré une très élégante, que je partagerai avec vous. Cela nécessite du JS, mais pas beaucoup.

Imaginez que vous ayez une div d'une taille dans laquelle vous devez mettre votre étiquette:

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

Maintenant, vous avez une fonction qui prendra deux paramètres: une chaîne avec l’étiquette, et un élément DOM (this div) pour l’adapter à: 

function setEllipsisLabel(div, label) 

La première chose à faire est de créer une span avec cette étiquette et de la placer dans la div:

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

Nous avons défini la propriété text-overflow sur "Ellipsis" afin que, lorsque le texte est découpé, un Nice "..." soit ajouté à la fin pour illustrer ceci. Nous avons également défini display sur "inline-block" afin que ces éléments aient des dimensions en pixels réelles que nous pourrons manipuler ultérieurement. Jusqu'à présent, rien ne pouvait être fait avec du CSS pur.

Mais nous voulons les Ellipsis au milieu. Premièrement, nous devrions savoir si nous en avons besoin du tout ... Cela peut être fait en comparant div.clientWidth à span.clientWidth - Ellipsis n’est nécessaire que si la span est plus large que la div.

Si nous avons besoin d'un Ellipsis, commençons par dire que nous voulons un nombre fixe de caractères affichés à la fin du mot - disons 10. Créez donc une étendue contenant uniquement les 10 derniers caractères de l'étiquette et collez-la dans le div:

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

Maintenant, remplaçons la largeur de la span originale pour tenir compte de la nouvelle:

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

À la suite de cela, nous avons maintenant une structure DOM qui ressemble à ceci:

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

Étant donné que la première span a text-overflow défini sur "Ellipsis", il indiquera "..." à la fin, suivi des 10 caractères de la deuxième plage, de sorte que les ellipsis apparaissent approximativement au milieu de la div.

Vous n'avez pas besoin non plus de coder en dur la longueur de 10 caractères pour endSpan: cela peut être approximé en calculant le rapport entre la largeur initiale de span et celle de div, en soustrayant la proportion appropriée de la longueur de l'étiquette et en divisant par deux.

3
levik

Vous ne pouvez pas faire cela avec CSS. Le problème est que HTML et CSS sont supposés fonctionner dans une variété de navigateurs et de polices et qu'il est presque impossible de calculer la largeur d'une chaîne de manière cohérente. Ceci est une idée qui pourrait vous aider. Cependant, vous devrez le faire plusieurs fois, jusqu'à ce que vous trouviez la chaîne avec la largeur appropriée.

3
kgiannakakis

Après quelques recherches sur les flex box, j'ai trouvé cette solution CSS pure qui, à mon avis, est plutôt cool. 

<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>
2
Nikola Schou

Cela vous donnera un peu plus de contrôle sur la position de l’ellipsis et du texte de substitution:

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

Vous pouvez appeler cette fonction en appelant:

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

Pour faire une coupe nette et avoir un mot entier à la fin du texte raccourci, j'ai utilisé la fonction ci-dessous.

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>

0
aero

Voici le bit le plus court que j'ai pu trouver qui remplace 3 caractères au milieu par ....

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

Un autre coup de couteau:

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) 
0
bob

Je viens de créer une fonction qui peut être ajustée au milieu, à proximité de End et End, mais je n’ai pas encore été testée car j’en avais enfin besoin du côté serveur.

//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) + '...';
        }
    }
}
0
Menelaos Vergis