web-dev-qa-db-fra.com

Détection d'ellipses de dépassement de texte HTML

J'ai une collection d'éléments de bloc sur une page. Ils ont tous les règles CSS espace-blanc, débordement, débordement de texte définies de sorte que le texte débordant soit coupé et qu'un Ellipsis soit utilisé.

Cependant, tous les éléments ne débordent pas.

Est-ce que je peux quand même utiliser javascript pour détecter quels éléments débordent?

Merci.

Ajouté: exemple de structure HTML avec laquelle je travaille.

<td><span>Normal text</span></td>
<td><span>Long text that will be trimmed text</span></td>

Les éléments SPAN tiennent toujours dans les cellules, la règle Ellipsis est appliquée. Je souhaite détecter le moment où l’Ellipsis est appliqué au contenu textuel du SPAN.

152
deanoj

Jadis, j’avais besoin de faire cela, et la seule solution fiable multi-navigateurs à laquelle j’ai eu à faire face est le piratage. Je ne suis pas le plus grand fan de solutions comme celle-ci, mais cela produit certainement le résultat correct à maintes reprises.

L'idée est de cloner l'élément, de supprimer toute largeur de bordure et de vérifier si l'élément cloné est plus large que l'original. Si c'est le cas, vous savez qu'il aura été tronqué.

Par exemple, en utilisant jQuery:

var $element = $('#element-to-test');
var $c = $element
           .clone()
           .css({display: 'inline', width: 'auto', visibility: 'hidden'})
           .appendTo('body');

if( $c.width() > $element.width() ) {
    // text was truncated. 
    // do what you need to do
}

$c.remove();

J'ai fait un jsFiddle pour démontrer cela, http://jsfiddle.net/cgzW8/2/

Vous pouvez même créer votre propre pseudo-sélecteur personnalisé pour jQuery:

$.expr[':'].truncated = function(obj) {
  var $this = $(obj);
  var $c = $this
             .clone()
             .css({display: 'inline', width: 'auto', visibility: 'hidden'})
             .appendTo('body');

  var c_width = $c.width();
  $c.remove();

  if ( c_width > $this.width() )
    return true;
  else
    return false;
};

Ensuite, utilisez-le pour trouver des éléments

$truncated_elements = $('.my-selector:truncated');

Démo: http://jsfiddle.net/cgzW8/293/

Espérons que cela aide, hacky tel qu'il est.

105
Christian Varga

Essayez cette fonction JS en passant l’élément span en argument:

function isEllipsisActive(e) {
     return (e.offsetWidth < e.scrollWidth);
}
235
Italo Borssatto

En ajoutant à la réponse de italo, vous pouvez également le faire avec jQuery.

function isEllipsisActive($jQueryObject) {
    return ($jQueryObject.width() < $jQueryObject[0].scrollWidth);
}

En outre, comme Smoky l’a souligné, vous pouvez utiliser jQuery outerWidth () au lieu de width ().

function isEllipsisActive($jQueryObject) {
    return ($jQueryObject.outerWidth() < $jQueryObject[0].scrollWidth);
}
13
Alex K

Pour ceux qui utilisent (ou prévoient d’utiliser) la réponse acceptée de Christian Varga, veuillez prendre en compte les problèmes de performances.

Le clonage/manipulation du DOM de telle manière provoque une redistribution de DOM (voir ne explication sur la redistribution du DOM ici), ce qui constitue une ressource extrêmement précieuse. intensif.

L'utilisation de la solution de Christian Varga sur plus de 100 éléments sur une page a provoqué un délai de refusion de 4 secondes au cours duquel le thread JS est verrouillé. Considérant que JS est mono-thread, cela signifie un retard UX important pour l'utilisateur final.

Italo Borssatto's answer devrait être celui qui a été accepté, il était environ 10 fois plus rapide lors de mon profilage.

7
RyanGled

elem.offsetWdith VS ele.scrollWidth Ce travail pour moi! https://jsfiddle.net/gustavojuan/210to9p1/

$(function() {
  $('.endtext').each(function(index, elem) {
    debugger;
    if(elem.offsetWidth !== elem.scrollWidth){
      $(this).css({color: '#FF0000'})
    }
  });
});
5
Gustavo Juan

La solution la plus simple (et multi-navigateur) compare réellement scrollWidth à clientWidth

Code de travail ici: https://stackoverflow.com/a/19156627/1213445

5
NicolasBernier

Cet exemple affiche une info-bulle sur une table de cellules avec du texte tronqué. Est dynamique en fonction de la largeur de la table:

$.expr[':'].truncated = function (obj) {
    var element = $(obj);

    return (element[0].scrollHeight > (element.innerHeight() + 1)) || (element[0].scrollWidth > (element.innerWidth() + 1));
};

$(document).ready(function () {
    $("td").mouseenter(function () {
        var cella = $(this);
        var isTruncated = cella.filter(":truncated").length > 0;
        if (isTruncated) 
            cella.attr("title", cella.text());
        else 
            cella.attr("title", null);
    });
});

Démo: https://jsfiddle.net/t4qs3tqs/

Cela fonctionne sur toutes les versions de jQuery

4
Red

Réponse de italo est très bon! Cependant laissez-moi l'affiner un peu:

function isEllipsisActive(e) {
   var tolerance = 2; // In px. Depends on the font you are using
   return e.offsetWidth + tolerance < e.scrollWidth;
}

Compatibilité entre navigateurs

Si, en fait, vous essayez le code ci-dessus et utilisez console.log pour afficher les valeurs de e.offsetWidth et e.scrollWidth, vous remarquerez sur IE que, même sans troncature du texte, une différence de valeur de 1px ou 2px est expérimenté.

Donc, en fonction de la taille de la police utilisée, autorisez une certaine tolérance!

3
Andry

Je pense que le meilleur moyen de le détecter est d'utiliser getClientRects(), il semble que chaque recto ait la même hauteur. Nous pouvons donc calculer le nombre de lignes avec le nombre de valeurs différentes de top.

getClientRects fonctionne comme this

function getRowRects(element) {
    var rects = [],
        clientRects = element.getClientRects(),
        len = clientRects.length,
        clientRect, top, rectsLen, rect, i;

    for(i=0; i<len; i++) {
        has = false;
        rectsLen = rects.length;
        clientRect = clientRects[i];
        top = clientRect.top;
        while(rectsLen--) {
            rect = rects[rectsLen];
            if (rect.top == top) {
                has = true;
                break;
            }
        }
        if(has) {
            rect.right = rect.right > clientRect.right ? rect.right : clientRect.right;
            rect.width = rect.right - rect.left;
        }
        else {
            rects.Push({
                top: clientRect.top,
                right: clientRect.right,
                bottom: clientRect.bottom,
                left: clientRect.left,
                width: clientRect.width,
                height: clientRect.height
            });
        }
    }
    return rects;
}

getRowRects fonctionne comme this

vous pouvez détecter comme this

1
Defims

Toutes les solutions ne fonctionnaient pas vraiment pour moi, ce que fait travail était de comparer les éléments scrollWidth au scrollWidth de son parent (ou de son enfant, en fonction de l'élément a la gâchette).

Lorsque l'enfant scrollWidth est supérieur à ses parents, cela signifie .text-Ellipsis c'est actif.


Lorsque event est l'élément parent

function isEllipsisActive(event) {
    let el          = event.currentTarget;
    let width       = el.offsetWidth;
    let widthChild  = el.firstChild.offsetWidth;
    return (widthChild >= width);
}

Lorsque event est l'élément enfant

function isEllipsisActive(event) {
    let el          = event.currentTarget;
    let width       = el.offsetWidth;
    let widthParent = el.parentElement.scrollWidth;
    return (width >= widthParent);
}
1
Jeffrey Roosendaal

Le e.offsetWidth < e.scrollWidth La solution ne fonctionne pas toujours.

Et si vous voulez utiliser du JavaScript pur, je vous recommande d'utiliser ceci:

(Manuscrit)

public isEllipsisActive(element: HTMLElement): boolean {
    element.style.overflow = 'initial';
    const noEllipsisWidth = element.offsetWidth;
    element.style.overflow = 'hidden';
    const ellipsisWidth = element.offsetWidth;

    if (ellipsisWidth < noEllipsisWidth) {
      return true;
    } else {
      return false;
    }
}
0
Sarel Zioni