HTML - Wie kann ich Tooltip NUR anzeigen, wenn die Auslassungspunkte aktiviert sind?

205

Ich habe eine Spanne mit dynamischen Daten auf meiner Seite, mit ellipsisStil.

.my-class
{
  text-overflow: ellipsis;
  overflow: hidden;
  white-space: nowrap;  
  width: 71px;
}
<span id="myId" class="my-class"></span>
document.getElementById('myId').innerText = "...";

Ich möchte diesem Element einen Tooltip mit demselben Inhalt hinzufügen, aber ich möchte, dass er nur angezeigt wird, wenn der Inhalt lang ist und die Auslassungspunkte auf dem Bildschirm angezeigt werden.

Gibt es eine Möglichkeit, dies zu tun?
Löst der Browser ein Ereignis aus, wenn ellipsises aktiviert ist?

* Browser: Internet Explorer

Spider Man
quelle
1
Denken Sie daran, dass text-overflow:ellipsis;dies in Firefox überhaupt nicht funktioniert - siehe diese Frage für weitere Informationen
Spudley
2
Ich musste nur etwas Ähnliches tun. Überprüfen, ob element.offsetWidth < element.scrollWidthgemäß dieser Antwort bisher zu funktionieren scheint.
Martin Smith
7
Hinweis für die Nachwelt: Funktioniert text-overflow:ellipsis;jetzt in Firefox; Es wurde in Firefox 7 hinzugefügt (veröffentlicht im September 2011).
Sleske

Antworten:

161

Hier ist eine Möglichkeit, die mithilfe der integrierten Ellipseneinstellung erfolgt und das titleAttribut On-Demand (mit jQuery) auf der Grundlage von Martin Smiths Kommentar hinzufügt :

$('.mightOverflow').bind('mouseenter', function(){
    var $this = $(this);

    if(this.offsetWidth < this.scrollWidth && !$this.attr('title')){
        $this.attr('title', $this.text());
    }
});
Jason Kleban
quelle
4
Danke, funktioniert wie ein Zauber! Wenn Sie es jedoch effizienter gestalten möchten, können Sie bind () durch on () wie folgt ersetzen: $ (document) .on ('mouseenter', '.mightOverflow', function () {...});
Ziad
17
Wenn Sie möchten, dass der Tooltip automatisch entfernt wird, wenn der Text nicht mehr überläuft, ändern Sie ihn in: $ (document) .on ('mouseenter', '.mightOverflow', function () {var $ t = $ (this); var title = $ t.attr ('title'); if (! title) {if (this.offsetWidth <this.scrollWidth) $ t.attr ('title', $ t.text ())} else {if (this.offsetWidth> = this.scrollWidth && title == $ t.text ()) $ t.removeAttr ('title')}});
Chris Janssen
1
mouseenter ist das Ereignis, an das wir binden oder auf das wir warten. Wir müssen den Tooltip erst dann zu den Elementen hinzufügen, wenn jemand tatsächlich mit der Maus darüber fährt. Daher verschieben wir die Addition bis zu diesem Punkt des Mouseenter für eines der DOM-Elemente mit der Klasse "möglicherweise Überlauf". Just-In-Time-Tooltips
Jason Kleban
2
"As of jQuery 1.7, the .on() method is the preferred method for attaching event handlers to a document"Weitere Informationen finden Sie unter api.jquery.com/bind und api.jquery.com/on
Adrien Be
2
Unter IE10 funktioniert es nicht - offsetWidth ist identisch mit scrollWidth. Beide geben mir die abgeschnittene Breite.
SsjCosty
59

Hier ist eine reine CSS-Lösung. Keine Notwendigkeit für jQuery. Es wird kein Tooltip angezeigt, sondern der Inhalt wird beim Mouseover nur auf seine volle Länge erweitert.

Funktioniert hervorragend, wenn Sie Inhalte haben, die ersetzt werden. Dann müssen Sie nicht jedes Mal eine jQuery-Funktion ausführen.

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

.might-overflow:hover {
    text-overflow: clip;
    white-space: normal;
    word-break: break-all;
}
Snæbjørn
quelle
17
Es ist nicht so gut wie ein Tooltip, da es das Layout beschädigen kann.
Alexander
2
Das Problem mit Tooltips ist, dass sie zumindest vorerst nicht auf Mobilgeräten funktionieren. Diese Antwort könnte (lesen: wird wahrscheinlich) das Layout beschädigen, könnte aber angepasst werden, um beispielsweise eine andere Hintergrundfarbe für das schwebende Element zu haben. Dies würde auf Mobilgeräten immer noch nicht funktionieren, ist jedoch eine weitere Option für den Desktop.
Tryse
1
Vielen Dank für diese großartige Antwort, die meine Bedürfnisse perfekt abdeckt. Mit etwas JavaScript könnten wir uns vorstellen, den Block absolut positioniert zu machen, damit das Layout nicht beschädigt wird.
Niavlys
2
Es ist eine nette Antwort, besser als Javascript in einem CSS-Problem aufzublähen. Es ist klar, dass Auslassungspunkte eine automatisierte Titeloption haben sollten. Die Art und Weise, wie sie derzeit implementiert wird, ist nicht sinnvoll. Schade, dass CSS nicht nur erlaubt: schwebe, wenn die letzten Zeichen '...' sind
John
32

Die Antwort von uosɐſ ist grundsätzlich richtig, aber Sie möchten sie wahrscheinlich nicht im mouseenter-Ereignis tun. Dies führt dazu, dass die Berechnung jedes Mal durchgeführt wird, um festzustellen, ob sie benötigt wird, wenn Sie mit der Maus über das Element fahren. Wenn sich die Größe des Elements nicht ändert, gibt es keinen Grund, dies zu tun.

Es ist besser, diesen Code sofort nach dem Hinzufügen des Elements zum DOM aufzurufen:

var $ele = $('#mightOverflow');
var ele = $ele.eq(0);
if (ele.offsetWidth < ele.scrollWidth)
    $ele.attr('title', $ele.text());

Wenn Sie nicht genau wissen, wann es hinzugefügt wurde, rufen Sie diesen Code auf, nachdem die Seite vollständig geladen wurde.

Wenn Sie mehr als ein einzelnes Element haben, mit dem Sie dies tun müssen, können Sie allen dieselbe Klasse geben (z. B. "mayOverflow") und diesen Code verwenden, um sie alle zu aktualisieren:

$('.mightOverflow').each(function() {
    var $ele = $(this);
    if (this.offsetWidth < this.scrollWidth)
        $ele.attr('title', $ele.text());
});
Elezar
quelle
+1, das Laden der Seite scheint einfacher zu sein, bietet aber auch mehr Möglichkeiten. dh. Möglicherweise möchten Sie dieses Element mit einem Tooltip mit einer gepunkteten Unterstreichung formatieren, um den Tooltip zu "signalisieren". wie$(".mightOverflow").each(function() { if( $(this).offsetWidth < $(this).scrollWidth && !$(this).attr('title')){ $(this).attr('title', $(this).text()); $(this).css('border-bottom', '1px dotted #A8A8A8'); } });
Adrien Be
"Jedes Mal, wenn Sie mit der Maus darüber fahren" ist falsch (zumindest jetzt - ich weiß nicht, ob die Antwort aktualisiert wurde). Es wird überprüft, ob sie zuvor berechnet wurde. "&&! $ this.attr (" title ")"
Rune Jeppesen
Nein, das verhindert nur, dass das title-Attribut erneut hinzugefügt wird. Die Berechnung, um festzustellen, ob es benötigt wird, ist noch nicht abgeschlossen. this.offsetWidth < this.scrollWidthund möglicherweise wird sogar die Überprüfung !$this.attr('title')jedes Mal durchgeführt, wenn Sie mit der Maus über das Element fahren.
Elezar
9
Das Problem bei dieser Methode besteht darin, dass alle Elemente auf einmal überprüft werden (potenzielle Auswirkungen auf die Leistung) und nur einmal berechnet werden. Wenn der Benutzer den Browser verkleinert, werden die Elemente abgeschnitten oder erweitert, sodass sie nicht mehr abgeschnitten werden Aktualisieren Sie das Vorhandensein eines Tooltips. Das erneute Anhängen Ihres Codes an die Fenstergröße hat ein Leistungsproblem, da jedes Element seine Größe überprüft. Wenn Sie die Ereignisdelegation "$ (document) .on ('mouseenter', '.mightOverflow', ..." verwenden und die Prüfung verzögern, bis Sie mit der Maus über das Element fahren, können Sie im laufenden Betrieb aktualisieren und jeweils nur 1 Element prüfen
Chris Janssen
Unter IE10 funktioniert es nicht - offsetWidth ist identisch mit scrollWidth. Beide geben mir die abgeschnittene Breite.
SsjCosty
18

Hier sind zwei weitere reine CSS-Lösungen:

  1. Zeigen Sie den abgeschnittenen Text an Ort und Stelle an:

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

.overflow:hover {
  overflow: visible;
}

.overflow:hover span {
  position: relative;
  background-color: white;

  box-shadow: 0 0 4px 0 black;
  border-radius: 1px;
}
<div>
  <span class="overflow" style="float: left; width: 50px">
    <span>Long text that might overflow.</span>
  </span>
  Lorem ipsum dolor sit amet, consectetur adipisicing elit. Ad recusandae perspiciatis accusantium quas aut explicabo ab. Doloremque quam eos, alias dolore, iusto pariatur earum, ullam, quidem dolores deleniti perspiciatis omnis.
</div>

  1. Zeigen Sie einen beliebigen "Tooltip" an :

.wrap {
  position: relative;
}

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

.overflow:after {
  content:"";
  display: block;
  position: absolute;
  top: 0;
  right: 0;
  width: 20px;
  height: 15px;
  z-index: 1;
  border: 1px solid red; /* for visualization only */
  pointer-events:initial;

}

.overflow:hover:after{
  cursor: pointer;
}

.tooltip {
  /* visibility: hidden; */
  display: none;
  position: absolute;
  top: 10;
  left: 0;
  background-color: #fff;
  padding: 10px;
  -webkit-box-shadow: 0 0 50px 0 rgba(0,0,0,0.3);
  opacity: 0;
  transition: opacity 0.5s ease;
}


.overflow:hover + .tooltip {
  /*visibility: visible; */
  display: initial;
  transition: opacity 0.5s ease;
  opacity: 1;
}
<div>
  <span class="wrap">
    <span class="overflow" style="float: left; width: 50px">Long text that might overflow</span>
    <span class='tooltip'>Long text that might overflow.</span>
  </span>
  Lorem ipsum dolor sit amet, consectetur adipisicing elit. Ad recusandae perspiciatis accusantium quas aut explicabo ab. Doloremque quam eos, alias dolore, iusto pariatur earum, ullam, quidem dolores deleniti perspiciatis omnis.
</div>

Hannes
quelle
Genau das habe ich gesucht!
Praneet Nadkar
Hervorragende Lösung, genau das, was ich brauche. Danke !
Agu V
17

Hier ist mein jQuery-Plugin:

(function($) {
    'use strict';
    $.fn.tooltipOnOverflow = function() {
        $(this).on("mouseenter", function() {
            if (this.offsetWidth < this.scrollWidth) {
                $(this).attr('title', $(this).text());
            } else {
                $(this).removeAttr("title");
            }
        });
    };
})(jQuery);

Verwendung:

$("td, th").tooltipOnOverflow();

Bearbeiten:

Ich habe einen Kern für dieses Plugin gemacht. https://gist.github.com/UziTech/d45102cdffb1039d4415

Tony Brix
quelle
1
Unter IE10 funktioniert es nicht - offsetWidth ist identisch mit scrollWidth. Beide geben mir die abgeschnittene Breite.
SsjCosty
@SsjCosty warum testest du auf IE 10? Zu diesem Zeitpunkt sollte niemand IE 10 verwenden, da jeder, der IE 10 installieren kann, IE 11 installieren kann.
Tony Brix
Nun gut, wir haben eine Unternehmensrichtlinie, nach der unsere Mindest-IE-Version 10 unterstützt. Auch weil viele unserer Kunden (einige Banken und verschiedene Institutionen) immer noch IE10 verwenden. Naja.
SsjCosty
12

Wir müssen erkennen, ob die Auslassungspunkte wirklich angewendet werden, und dann einen Tooltip anzeigen, um den Volltext anzuzeigen. Es reicht nicht aus, nur " this.offsetWidth < this.scrollWidth" zu vergleichen, wenn das Element fast seinen Inhalt enthält, sondern nur ein oder zwei weitere Pixel in der Breite fehlen, insbesondere für den Text von chinesischen / japanischen / koreanischen Zeichen in voller Breite.

Hier ist ein Beispiel: http://jsfiddle.net/28r5D/5/

Ich habe einen Weg gefunden, die Ellipsenerkennung zu verbessern:

  1. Vergleichen Sie zuerst " this.offsetWidth < this.scrollWidth" und fahren Sie mit Schritt 2 fort, falls dies fehlschlägt.
  2. Schalten Sie den CSS-Stil zeitlich auf {'Überlauf': 'sichtbar', 'Leerraum': 'normal', 'Wortumbruch': 'Umbruch'}.
  3. Lassen Sie den Browser Relayout ausführen. Wenn ein Zeilenumbruch stattfindet, erweitert das Element seine Höhe, was auch bedeutet, dass Auslassungspunkte erforderlich sind.
  4. Stellen Sie den CSS-Stil wieder her.

Hier ist meine Verbesserung: http://jsfiddle.net/28r5D/6/

Feng Dihai
quelle
10

Ich habe ein jQuery-Plugin erstellt, das den Tooltip von Bootstrap anstelle des integrierten Tooltips des Browsers verwendet. Bitte beachten Sie, dass dies nicht mit einem älteren Browser getestet wurde.

JSFiddle: https://jsfiddle.net/0bhsoavy/4/

$.fn.tooltipOnOverflow = function(options) {
    $(this).on("mouseenter", function() {
    if (this.offsetWidth < this.scrollWidth) {
        options = options || { placement: "auto"}
        options.title = $(this).text();
      $(this).tooltip(options);
      $(this).tooltip("show");
    } else {
      if ($(this).data("bs.tooltip")) {
        $tooltip.tooltip("hide");
        $tooltip.removeData("bs.tooltip");
      }
    }
  });
};
Steven
quelle
Einfach und brillant. Danke dir!
GumZ
3

Das habe ich getan. Bei den meisten Tooltip-Skripten müssen Sie eine Funktion ausführen, in der die Tooltips gespeichert sind. Dies ist ein jQuery-Beispiel:

$.when($('*').filter(function() {
   return $(this).css('text-overflow') == 'ellipsis';
}).each(function() {
   if (this.offsetWidth < this.scrollWidth && !$(this).attr('title')) {
      $(this).attr('title', $(this).text());
   }
})).done(function(){ 
   setupTooltip();
});

Wenn Sie nicht nach Auslassungspunkten suchen möchten, können Sie Folgendes vereinfachen:

$.when($('*').filter(function() {
   return (this.offsetWidth < this.scrollWidth && !$(this).attr('title'));
}).each(function() {
   $(this).attr('title', $(this).text());
})).done(function(){ 
   setupTooltip();
});

Ich habe das "Wann" um mich herum, so dass die "setupTooltip" -Funktion erst ausgeführt wird, wenn alle Titel aktualisiert wurden. Ersetzen Sie den "setupTooltip" durch Ihre Tooltip-Funktion und das * durch die Elemente, die Sie überprüfen möchten. * wird sie alle durchgehen, wenn Sie es verlassen.

Wenn Sie einfach nur die Titelattribute mit dem Tooltip des Browsers aktualisieren möchten, können Sie Folgendes vereinfachen:

$('*').filter(function() {
   return $(this).css('text-overflow') == 'ellipsis';
}).each(function() {
   if (this.offsetWidth < this.scrollWidth && !$(this).attr('title')) {
      $(this).attr('title', $(this).text());
   }
});

Oder ohne Überprüfung auf Auslassungspunkte:

$.when($('*').filter(function() {
   return (this.offsetWidth < this.scrollWidth && !$(this).attr('title'));
}).each(function() {
   $(this).attr('title', $(this).text());
});
Fanfavorit
quelle
Warum das Downvote? Bitte kommentieren Sie, wenn Sie dies tun, damit die Leute wissen, wo das Problem liegt. Vielen Dank.
Fanfavorit
2

Wenn Sie dies ausschließlich mit Javascript tun möchten, würde ich Folgendes tun. Geben Sie dem Bereich ein ID-Attribut (damit es leicht aus dem DOM abgerufen werden kann) und platzieren Sie den gesamten Inhalt in einem Attribut mit dem Namen "Inhalt":

<span id='myDataId' style='text-overflow: ellipsis; overflow : hidden;
 white-space: nowrap; width: 71;' content='{$myData}'>${myData}</span>

In Ihrem Javascript können Sie dann Folgendes tun, nachdem das Element in das DOM eingefügt wurde.

var elemInnerText, elemContent;
elemInnerText = document.getElementById("myDataId").innerText;
elemContent = document.getElementById("myDataId").getAttribute('content')
if(elemInnerText.length <= elemContent.length)
{
   document.getElementById("myDataId").setAttribute('title', elemContent); 
}

Wenn Sie Javascript verwenden, um den Bereich in das DOM einzufügen, können Sie den Inhalt natürlich vor dem Einfügen in einer Variablen belassen. Auf diese Weise benötigen Sie kein Inhaltsattribut für den Bereich.

Es gibt elegantere Lösungen als diese, wenn Sie jQuery verwenden möchten.

Mark Costello
quelle
Nett. Da ich JQuery in einem anderen Teil dieser Seite verwende - was ist die elegante JQuery-Lösung?
Spiderman
$("#myDataId").attr("title", function() { var innerText = $(this).text(); var content = $(this).attr("content"); if (innerText.length <= content.length) { return content; } return null; });
Mark Costello
1
Ich habe Ihren ersten Vorschlag mit reinem Javascript versucht - es funktioniert nicht. Die Eigenschaft 'innerText' speichert die gesamte Länge des Textes, auch wenn er nicht immer vollständig auf dem Bildschirm angezeigt wird: elemInnerText.length == elemContent.length !!
Spiderman
Der Stil Ihrer Spanne ist Breite 71. Überprüfen Sie, ob die Breite der Zeichenfolge länger ist. Wenn Sie etwas wirklich Funky machen möchten, können Sie ein verstecktes Element ohne den Textüberlauf hinzufügen: Ellipsen setzen und die Breiten beider vergleichen. Wenn das versteckte breiter als das nicht versteckte ist, fügen Sie dem sichtbaren ein Titelattribut hinzu.
Mark Costello
2

Ich habe eine CSS-Klasse, die bestimmt, wo Auslassungspunkte gesetzt werden sollen. Basierend darauf mache ich Folgendes (Elementmenge könnte unterschiedlich sein, ich schreibe diejenigen, bei denen Auslassungspunkte verwendet werden, natürlich könnte es ein separater Klassenselektor sein):

$(document).on('mouseover', 'input, td, th', function() {
    if ($(this).css('text-overflow') && typeof $(this).attr('title') === 'undefined') {
        $(this).attr('title', $(this).val());
    }
});
Alexander
quelle
1
Ich mein Fall thiswar ein anchorso, dass ich this.text()anstelle vonval()
Basheer AL-MOMANI
2

Hier ist eine Vanilla JavaScript-Lösung:

(function init() {

  var cells = document.getElementsByClassName("cell");

  for(let index = 0; index < cells.length; ++index) {
    let cell = cells.item(index);
    cell.addEventListener('mouseenter', setTitleIfNecessary, false);
  }

  function setTitleIfNecessary() {
    if(this.offsetWidth < this.scrollWidth) {
      this.setAttribute('title', this.innerHTML);
    }
  }

})();
.cell {
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  border: 1px;
  border-style: solid;
  width: 120px; 
}
<div class="cell">hello world!</div>
<div class="cell">hello mars! kind regards, world</div>

Wuarmin
quelle
1

Das war meine Lösung, wirkt wie ein Zauber!

    $(document).on('mouseover', 'input, span', function() {
      var needEllipsis = $(this).css('text-overflow') && (this.offsetWidth < this.scrollWidth);
      var hasNotTitleAttr = typeof $(this).attr('title') === 'undefined';
      if (needEllipsis === true) {
          if(hasNotTitleAttr === true){
            $(this).attr('title', $(this).val());
          }
      }
      if(needEllipsis === false && hasNotTitleAttr == false){
        $(this).removeAttr('title');
      }
  });
FarukT
quelle
Hallo @FarukT, deine Lösung funktioniert gut für mich, vielen Dank. Ich möchte fragen, ob ich zwei HTML-Tags habe, vorausgesetzt, input & span, und ich möchte die offsetWidth dieser beiden Tags gleichzeitig berechnen, um einige arithmetische Berechnungen mit diesen offsetWidth durchzuführen. Wie würde ich das machen?
Kunal Tyagi
Hallo @KunalTyagi, du kannst es mit 2 getrennten Funktionen machen, ich habe nur eine mit Eingabe und Spanne geschrieben, aber du kannst diese Funktion 2 Mal replizieren, zum Beispiel erste Funktion mit nur Eingabe und in der zweiten Funktion nur Spanne. wie folgt: $ (document) .on ('mouseover', 'input', function () {...}); und das zweite $ (document) .on ('mouseover', 'span', function () {...});
FarukT
0

Keine der oben genannten Lösungen hat bei mir funktioniert, aber ich habe eine großartige Lösung gefunden. Der größte Fehler, den Menschen machen, besteht darin, dass alle 3 CSS-Eigenschaften beim Laden der Seite für das Element deklariert werden. Sie müssen diese Stile + QuickInfo dynamisch hinzufügen, WENN und NUR WENN die Spanne, auf der Ellipsen angezeigt werden sollen, breiter ist als die übergeordnete.

    $('table').each(function(){
        var content = $(this).find('span').text();
        var span = $(this).find('span');
        var td = $(this).find('td');
        var styles = {
            'text-overflow':'ellipsis',
            'white-space':'nowrap',
            'overflow':'hidden',
            'display':'block',
            'width': 'auto'
        };
        if (span.width() > td.width()){
            span.css(styles)
                .tooltip({
                trigger: 'hover',
                html: true,
                title: content,
                placement: 'bottom'
            });
        }
    });
Brian Gabriel
quelle
0

Sie könnten die Spanne möglicherweise mit einer anderen Spanne umgeben und dann einfach testen, ob die Breite der ursprünglichen / inneren Spanne größer als die der neuen / äußeren Spanne ist. Beachten Sie, dass ich möglicherweise sage - es basiert ungefähr auf meiner Situation, in der ich ein spanInneres von a hatte, tdalso weiß ich nicht wirklich, ob es mit einem spanInneren von a funktioniert span.

Hier ist jedoch mein Code für andere, die sich möglicherweise in einer ähnlichen Position wie ich befinden. Ich kopiere / füge es ohne Änderung ein, obwohl es sich in einem Winkelkontext befindet. Ich denke nicht, dass dies die Lesbarkeit und das wesentliche Konzept beeinträchtigt. Ich habe es als Servicemethode codiert, weil ich es an mehr als einer Stelle anwenden musste. Der Selektor, den ich übergeben habe, war ein Klassenselektor, der mehreren Instanzen entspricht.

CaseService.applyTooltip = function(selector) {
    angular.element(selector).on('mouseenter', function(){
        var td = $(this)
        var span = td.find('span');

        if (!span.attr('tooltip-computed')) {
            //compute just once
            span.attr('tooltip-computed','1');

            if (span.width() > td.width()){
                span.attr('data-toggle','tooltip');
                span.attr('data-placement','right');
                span.attr('title', span.html());
            }
        }
    });
}
Sauerstoff
quelle