Überprüfen Sie, ob der Inhalt eines Elements überläuft.

152

Was ist der einfachste Weg, um festzustellen, ob ein Element übergelaufen ist?

Mein Anwendungsfall ist, dass ich ein bestimmtes Inhaltsfeld auf eine Höhe von 300 Pixel beschränken möchte. Wenn der innere Inhalt größer ist, schneide ich ihn mit einem Überlauf ab. Aber wenn es übergelaufen ist, möchte ich eine Schaltfläche "Mehr" anzeigen, aber wenn nicht, möchte ich diese Schaltfläche nicht anzeigen.

Gibt es eine einfache Möglichkeit, einen Überlauf zu erkennen, oder gibt es eine bessere Methode?

Harry
quelle

Antworten:

84

Wenn Sie nur einen Bezeichner für mehr Inhalt anzeigen möchten, können Sie dies mit reinem CSS tun. Ich benutze dafür reine Scrolling-Schatten. Der Trick ist die Verwendung von background-attachment: local;. Ihr CSS sieht so aus:

.scrollbox {
  overflow: auto;
  width: 200px;
  max-height: 200px;
  margin: 50px auto;

  background:
    /* Shadow covers */
    linear-gradient(white 30%, rgba(255,255,255,0)),
    linear-gradient(rgba(255,255,255,0), white 70%) 0 100%,
    
    /* Shadows */
    radial-gradient(50% 0, farthest-side, rgba(0,0,0,.2), rgba(0,0,0,0)),
    radial-gradient(50% 100%,farthest-side, rgba(0,0,0,.2), rgba(0,0,0,0)) 0 100%;
  background:
    /* Shadow covers */
    linear-gradient(white 30%, rgba(255,255,255,0)),
    linear-gradient(rgba(255,255,255,0), white 70%) 0 100%,
    
    /* Shadows */
    radial-gradient(farthest-side at 50% 0, rgba(0,0,0,.2), rgba(0,0,0,0)),
    radial-gradient(farthest-side at 50% 100%, rgba(0,0,0,.2), rgba(0,0,0,0)) 0 100%;
  background-repeat: no-repeat;
  background-color: white;
  background-size: 100% 40px, 100% 40px, 100% 14px, 100% 14px;
  
  /* Opera doesn't support this in the shorthand */
  background-attachment: local, local, scroll, scroll;
}
<div class="scrollbox">
  <ul>
    <li>Not enough content to scroll</li>
    <li>2</li>
    <li>3</li>
    <li>4</li>
    <li>5</li>
  </ul>
</div>


<div class="scrollbox">
  <ul>
    <li>Ah! Scroll below!</li>
    <li>2</li>
    <li>3</li>
    <li>4</li>
    <li>5</li>
    <li>6</li>
    <li>7</li>
    <li>8</li>
    <li>9</li>
    <li>10</li>
    <li>1</li>
    <li>2</li>
    <li>3</li>
    <li>4</li>
    <li>5</li>
    <li>6</li>
    <li>7</li>
    <li>8</li>
    <li>The end!</li>
    <li>No shadow there.</li>
  </ul>
</div>

Den Code und das Beispiel finden Sie unter http://dabblet.com/gist/2462915

Eine Erklärung finden Sie hier: http://lea.verou.me/2012/04/background-attachment-local/ .

RWAM
quelle
1
Gute Idee, aber in Ihrem Beispiel wäre der Hintergrund (Schatten) hinter dem Text!
DreamTeK
Toller Trick, aber in Chrome zeigt es nur statischen Schatten auf der Unterseite, es verschwindet nie und der obere Schatten zeigt nie
Jared
214

Das Element kann vertikal, horizontal oder beides überflogen werden. Diese Funktion gibt einen booleschen Wert zurück, wenn das DOM-Element übergelaufen ist:

function isOverflown(element) {
  return element.scrollHeight > element.clientHeight || element.scrollWidth > element.clientWidth;
}

ES6-Beispiel:

const isOverflown = ({ clientWidth, clientHeight, scrollWidth, scrollHeight }) => {
    return scrollHeight > clientHeight || scrollWidth > clientWidth;
}
micnic
quelle
41
Tolle Lösung! Hier ist eine jQuery-Variante (zur Verwendung mit $("#element").overflown()):$.fn.overflown=function(){var e=this[0];return e.scrollHeight>e.clientHeight||e.scrollWidth>e.clientWidth;}
Sygmoral
@micnic Hallo, ich benutze ionic2 und versuche das gleiche zu tun ... aber die Funktion gibt immer true zurück ... gibt es eine andere Möglichkeit, Dinge in Winkel 2 zu tun
Yasir
@ DavidBracoly, diese Funktion ist für reine DOM-API, ich habe keine Erfahrung mit Ionic / Angular, ich denke, Sie sollten das ursprüngliche DOM-Element erhalten und diese Funktion verwenden
micnic
3
Nur für Firefox: element.addEventListener ("overflow", () => log( "overflow" ), false);Referenz: Überlaufereignis
Reza
17

Im Vergleich element.scrollHeightzu element.clientHeightsollte die Aufgabe erledigen.

Unten sehen Sie die Bilder von MDN, die Element.scrollHeight und Element.clientHeight erläutern.

Bildlaufhöhe

Kundenhöhe

Bergi
quelle
2
Ja, aber laut quirksmode funktioniert es am besten - und ist viel einfacher als die anderen veröffentlichten Lösungen.
Bergi
@Harry: Es wird in allen aktuellen Browsern unterstützt (zumindest auf Desktop-Browsern), daher spielt es keine Rolle, dass es formal nicht dem Standard entspricht.
Marat Tanalin
1
Hier haben diese Eigenschaften immer die gleichen Werte.
Koppor
6

Ich habe einen mehrteiligen Codepen erstellt, der die obigen Antworten demonstriert (z. B. unter Verwendung von verstecktem Überlauf und Höhe), aber auch, wie Sie übergelaufene Elemente erweitern / reduzieren würden

Beispiel 1: https://codepen.io/Kagerjay/pen/rraKLB (Wirklich einfaches Beispiel, kein Javascript, nur um übergelaufene Elemente zu beschneiden)

Beispiel 2: https://codepen.io/Kagerjay/pen/LBErJL (Einzelereignishandler zeigt mehr / Showless bei übergelaufenen Elementen an)

Beispiel 3: https://codepen.io/Kagerjay/pen/MBYBoJ (Multi-Event-Handler bei vielen zeigen mehr / weniger bei übergelaufenen Elementen)

Ich habe auch Beispiel 3 unten angehängt. Ich verwende Jade / Mops, damit es ein bisschen ausführlich ist. Ich schlage vor, die Codepens zu überprüfen, die ich einfacher zu verstehen gemacht habe.

// Overflow boolean checker
function isOverflown(element){
  return element.scrollHeight > element.clientHeight || element.scrollWidth > element.clientWidth;
}

// Jquery Toggle Text Plugin
$.fn.toggleText = function(t1, t2){
  if (this.text() == t1) this.text(t2);
  else                   this.text(t1);
  return this;
};

// Toggle Overflow
function toggleOverflow(e){
  e.target.parentElement.classList.toggle("grid-parent--showall");
  $(e.target).toggleText("Show More", "Show LESS");
}

// Where stuff happens
var parents = document.querySelectorAll(".grid-parent");

parents.forEach(parent => {
  if(isOverflown(parent)){
    parent.lastElementChild.classList.add("btn-show");
    parent.lastElementChild.addEventListener('click', toggleOverflow);
  }
})
body {
  background-color: #EEF0ED;
  margin-bottom: 300px;
}

.grid-parent {
  margin: 20px;
  width: 250px;
  background-color: lightgrey;
  display: flex;
  flex-wrap: wrap;
  overflow: hidden;
  max-height: 100px;
  position: relative;
}
.grid-parent--showall {
  max-height: none;
}

.grid-item {
  background-color: blue;
  width: 50px;
  height: 50px;
  box-sizing: border-box;
  border: 1px solid red;
}
.grid-item:nth-of-type(even) {
  background-color: lightblue;
}

.btn-expand {
  display: none;
  z-index: 3;
  position: absolute;
  right: 0px;
  bottom: 0px;
  padding: 3px;
  background-color: red;
  color: white;
}

.btn-show {
  display: block;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<section>
  <p>Any grid-parent over 10 child items has a "SHOW MORE" button to expand</p>
  <p>Click "SHOW MORE" to see the results</p>
</section>
<radio></radio>
<div class="wrapper">
  <h3>5 child elements</h3>
  <div class="grid-parent">
    <div class="grid-item"></div>
    <div class="grid-item"></div>
    <div class="grid-item"></div>
    <div class="grid-item"></div>
    <div class="grid-item"></div>
    <div class="btn-expand">Show More</div>
  </div>
  <h3>8 child elements</h3>
  <div class="grid-parent">
    <div class="grid-item"></div>
    <div class="grid-item"></div>
    <div class="grid-item"></div>
    <div class="grid-item"></div>
    <div class="grid-item"></div>
    <div class="grid-item"></div>
    <div class="grid-item"></div>
    <div class="grid-item"></div>
    <div class="btn-expand">Show More</div>
  </div>
  <h3>10 child elements</h3>
  <div class="grid-parent">
    <div class="grid-item"></div>
    <div class="grid-item"></div>
    <div class="grid-item"></div>
    <div class="grid-item"></div>
    <div class="grid-item"></div>
    <div class="grid-item"></div>
    <div class="grid-item"></div>
    <div class="grid-item"></div>
    <div class="grid-item"></div>
    <div class="grid-item"></div>
    <div class="btn-expand">Show More</div>
  </div>
  <h3>13 child elements</h3>
  <div class="grid-parent">
    <div class="grid-item"></div>
    <div class="grid-item"></div>
    <div class="grid-item"></div>
    <div class="grid-item"></div>
    <div class="grid-item"></div>
    <div class="grid-item"></div>
    <div class="grid-item"></div>
    <div class="grid-item"></div>
    <div class="grid-item"></div>
    <div class="grid-item"></div>
    <div class="grid-item"></div>
    <div class="grid-item"></div>
    <div class="grid-item"></div>
    <div class="btn-expand">Show More</div>
  </div>
  <h3>16 child elements</h3>
  <div class="grid-parent">
    <div class="grid-item"></div>
    <div class="grid-item"></div>
    <div class="grid-item"></div>
    <div class="grid-item"></div>
    <div class="grid-item"></div>
    <div class="grid-item"></div>
    <div class="grid-item"></div>
    <div class="grid-item"></div>
    <div class="grid-item"></div>
    <div class="grid-item"></div>
    <div class="grid-item"></div>
    <div class="grid-item"></div>
    <div class="grid-item"></div>
    <div class="grid-item"></div>
    <div class="grid-item"></div>
    <div class="grid-item"></div>
    <div class="btn-expand">Show More</div>
  </div>
  <h3>19 child elements</h3>
  <div class="grid-parent">
    <div class="grid-item"></div>
    <div class="grid-item"></div>
    <div class="grid-item"></div>
    <div class="grid-item"></div>
    <div class="grid-item"></div>
    <div class="grid-item"></div>
    <div class="grid-item"></div>
    <div class="grid-item"></div>
    <div class="grid-item"></div>
    <div class="grid-item"></div>
    <div class="grid-item"></div>
    <div class="grid-item"></div>
    <div class="grid-item"></div>
    <div class="grid-item"></div>
    <div class="grid-item"></div>
    <div class="grid-item"></div>
    <div class="grid-item"></div>
    <div class="grid-item"></div>
    <div class="grid-item"></div>
    <div class="btn-expand">Show More</div>
  </div>
</div>

Vincent Tang
quelle
4

Würde so etwas funktionieren : http://jsfiddle.net/Skooljester/jWRRA/1/ ? Es überprüft lediglich die Höhe des Inhalts und vergleicht ihn mit der Höhe des Containers. Wenn es größer ist als Sie, können Sie den Code eingeben, um eine Schaltfläche "Mehr anzeigen" anzuhängen.

Update: Der Code wurde hinzugefügt, um oben im Container eine Schaltfläche "Mehr anzeigen" zu erstellen.

Ayyp
quelle
3

Wenn Sie jQuery verwenden, können Sie einen Trick ausprobieren: Machen Sie ein äußeres Div mit overflow: hiddenund ein inneres Div mit Inhalt. Verwenden Sie dann die .height()Funktion, um zu überprüfen, ob die Höhe des inneren Teils größer als die Höhe des äußeren Teils ist. Ich bin nicht sicher, ob es funktionieren wird, aber probieren Sie es aus.

TMS
quelle
1

Verwenden Sie js, um zu überprüfen, ob das Kind offsetHeightmehr als die Eltern ist. Wenn dies der scroll/hidden/autoFall ist, lassen Sie die Eltern überlaufen, je nachdem, was Sie möchten, und auch display:blockauf der anderen Seite.

Vivek Chandra
quelle
1

Sie können die Grenzen relativ zum übergeordneten Versatz überprüfen.

// Position of left edge relative to frame left courtesy
// http://www.quirksmode.org/js/findpos.html
function absleft(el) {
  var x = 0;
  for (; el; el = el.offsetParent) {
    x += el.offsetLeft;
  }
  return x;
}

// Position of top edge relative to top of frame.
function abstop(el) {
  var y = 0;
  for (; el; el = el.offsetParent) {
    y += el.offsetTop;
  }
  return y;
}

// True iff el's bounding rectangle includes a non-zero area
// the container's bounding rectangle.
function overflows(el, opt_container) {
  var cont = opt_container || el.offsetParent;
  var left = absleft(el), right = left + el.offsetWidth,
      top = abstop(el), bottom = top + el.offsetHeight;
  var cleft = absleft(cont), cright = cleft + cont.offsetWidth,
      ctop = abstop(cont), cbottom = ctop + cont.offsetHeight;
  return left < cleft || top < ctop
      || right > cright || bottom > cbottom;
}

Wenn Sie diesem Element ein Element übergeben, werden Sie darüber informiert, ob sich seine Grenzen vollständig in einem Container befinden. Wenn kein expliziter Container angegeben ist, wird standardmäßig das übergeordnete Element des Elements verwendet. Es verwendet

Mike Samuel
quelle
1

Ein weiteres Problem, das Sie berücksichtigen sollten, ist die Nichtverfügbarkeit von JS. Denken Sie an fortschreitende Verzauberung oder anmutige Erniedrigung. Ich würde vorschlagen:

  • Standardmäßig wird "more button" hinzugefügt
  • Standardmäßig Überlaufregeln hinzufügen
  • Schaltfläche ausblenden und ggf. CSS-Änderungen in JS nach dem Vergleich von element.scrollHeight mit element.clientHeight
MFix
quelle
1

Hier ist eine Geige zum Bestimmen, ob ein Element mithilfe eines Wrapper-Div mit Überlauf übergelaufen ist: hidden und JQuery height (), um den Unterschied zwischen dem Wrapper und einem Div mit innerem Inhalt zu messen.

outers.each(function () {
    var inner_h = $(this).find('.inner').height();
    console.log(inner_h);
    var outer_h = $(this).height();
    console.log(outer_h);
    var overflowed = (inner_h > outer_h) ? true : false;
    console.log("overflowed = ", overflowed);
});

Quelle: Frameworks & Extensions auf jsfiddle.net

user1295799
quelle
1

Dies ist die jQuery-Lösung, die für mich funktioniert hat. clientWidthusw. hat nicht funktioniert.

function is_overflowing(element, extra_width) {
    return element.position().left + element.width() + extra_width > element.parent().width();
}

Wenn dies nicht funktioniert, stellen Sie sicher, dass das übergeordnete Element die gewünschte Breite hat (persönlich musste ich es verwenden parent().parent()). Es positionist relativ zum übergeordneten extra_widthElement . Ich habe es auch hinzugefügt, da meine Elemente ("Tags") Bilder enthalten, für die nur wenig Zeit erforderlich ist Laden, aber während des Funktionsaufrufs haben sie eine Breite von Null, was die Berechnung beeinträchtigt. Um dies zu umgehen, verwende ich den folgenden Aufrufcode:

var extra_width = 0;
$(".tag:visible").each(function() {
    if (!$(this).find("img:visible").width()) {
        // tag image might not be visible at this point,
        // so we add its future width to the overflow calculation
        // the goal is to hide tags that do not fit one line
        extra_width += 28;
    }
    if (is_overflowing($(this), extra_width)) {
        $(this).hide();
    }
});

Hoffe das hilft.

Dennis Golomazov
quelle
0
setTimeout(function(){
    isOverflowed(element)           
},500)

function isOverflowed(element){
    return element.scrollHeight > element.clientHeight || element.scrollWidth > element.clientWidth;
}

Das wurde für mich gearbeitet. Danke dir.

Krunal
quelle
3
Wie unterscheidet sich das von der Antwort von micnic?
Vorsicht am
0

Die jquery-Alternative zur Antwort besteht darin, mit der Taste [0] auf das Rohelement wie das folgende zuzugreifen:

if ($('#elem')[0].scrollHeight > $('#elem')[0].clientHeight){
Antonius
quelle
0

Ich habe Element aus Kapselungsgründen erweitert. Von Micnic Antwort.

/*
 * isOverflowing
 * 
 * Checks to see if the element has overflowing content
 * 
 * @returns {}
 */
Element.prototype.isOverflowing = function(){
    return this.scrollHeight > this.clientHeight || this.scrollWidth > this.clientWidth;
}

Verwenden Sie es so

let elementInQuestion = document.getElementById("id_selector");

    if(elementInQuestion.isOverflowing()){
        // do something
    }
David Clews
quelle