Verifica se il contenuto di un elemento è pieno?


154

Qual è il modo più semplice per rilevare se un elemento è stato traboccato?

Il mio caso d'uso è, voglio limitare una determinata casella di contenuto per avere un'altezza di 300 px. Se il contenuto interno è più alto di quello, lo taglio con un overflow. Ma se è traboccato, voglio mostrare un pulsante "Altro", ma in caso contrario non voglio mostrare quel pulsante.

Esiste un modo semplice per rilevare l'overflow o esiste un metodo migliore?

Risposte:


86

Se vuoi mostrare solo un identificatore per più contenuti, puoi farlo con CSS puro. Per questo uso ombre pure a scorrimento. Il trucco è l'uso di background-attachment: local;. Il tuo CSS si presenta così:

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

Il codice e l'esempio sono disponibili su http://dabblet.com/gist/2462915

E una spiegazione che puoi trovare qui: http://lea.verou.me/2012/04/background-attachment-local/ .


1
Bella idea ma nel tuo esempio lo sfondo (ombra) sarebbe dietro il testo!
DreamTeK,

Grande trucco, tuttavia in Chrome mostra solo un'ombra statica sul fondo, non scompare mai e l'ombra superiore non mostra mai
Jared

214

L'elemento può essere traboccato verticalmente, orizzontalmente o entrambi. Questa funzione ti restituirà un valore booleano se l'elemento DOM viene sovraccaricato:

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

Esempio ES6:

const isOverflown = ({ clientWidth, clientHeight, scrollWidth, scrollHeight }) => {
    return scrollHeight > clientHeight || scrollWidth > clientWidth;
}

41
Ottima soluzione! Ecco una variante jQuery (da utilizzare con $("#element").overflown()):$.fn.overflown=function(){var e=this[0];return e.scrollHeight>e.clientHeight||e.scrollWidth>e.clientWidth;}
Sygmoral

@micnic ciao, sto usando ionic2 e sto provando a fare la stessa cosa ... ma la funzione ritorna sempre vera ... c'è un modo diverso di fare le cose in angolare 2
Yasir il

@DavidBracoly, questa funzione è per l'API DOM pura, non ho esperienza con Ionic / Angular, suppongo che dovresti ottenere l'elemento DOM originale e utilizzare questa funzione
micnic

3
Solo per Firefox: element.addEventListener ("overflow", () => log( "overflow" ), false);Riferimento: evento di overflow
Reza,

18

Il confronto element.scrollHeightcon element.clientHeightdovrebbe fare il compito.

Di seguito sono riportate le immagini di MDN che spiegano Element.scrollHeight e Element.clientHeight.

Altezza di scorrimento

Altezza del cliente


2
Sì, ma secondo quirksmode funziona per lo più - ed è molto più semplice rispetto alle altre soluzioni pubblicate.
Bergi,

@Harry: è supportato in tutti i browser correnti (almeno quelli desktop), quindi non importa che sia formalmente non standard.
Marat Tanalin

1
Qui, queste proprietà hanno sempre gli stessi valori.
koppor,

7

Ho creato un codice in più parti che mostra le risposte sopra (ad es. Usando l'overflow nascosto e l'altezza) ma anche come espandere / comprimere gli oggetti traboccati

Esempio 1: https://codepen.io/Kagerjay/pen/rraKLB (Esempio semplice reale, senza javascript, solo per ritagliare elementi traboccati)

Esempio 2: https://codepen.io/Kagerjay/pen/LBErJL (il gestore di eventi singoli mostra di più / showless su elementi di overflow)

Esempio 3: https://codepen.io/Kagerjay/pen/MBYBoJ (il gestore di eventi multipli su molti mostra di più / mostra di meno su elementi di overflow)

Ho allegato anche l'esempio 3 di seguito , uso Jade / Pug, quindi potrebbe essere un po 'prolisso. Suggerisco di controllare i codici che ho reso più semplice da comprendere.

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


4

Qualcosa del genere: http://jsfiddle.net/Skooljester/jWRRA/1/ funzionerebbe? Controlla solo l'altezza del contenuto e lo confronta con l'altezza del contenitore. Se è maggiore di quello che puoi inserire nel codice per aggiungere un pulsante "Mostra altro".

Aggiornamento: aggiunto il codice per creare un pulsante "Mostra altro" nella parte superiore del contenitore.


3

Se stai usando jQuery, potresti provare un trucco: div div esterno con overflow: hiddendiv interno con contenuto. Quindi utilizzare la .height()funzione per verificare se l'altezza del div interno è maggiore dell'altezza del div esterno. Non sono sicuro che funzionerà, ma provalo.


1

usa js per verificare se il bambino offsetHeightè più dei genitori .. se lo è, fai traboccare i genitori scroll/hidden/autocome vuoi e anche display:blocksul più div ..


1

È possibile controllare i limiti relativi al genitore offset.

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

Se passi questo elemento, ti dirà se i suoi limiti sono interamente all'interno di un contenitore e, per impostazione predefinita, sarà il genitore offset dell'elemento se non viene fornito alcun contenitore esplicito. Utilizza


1

Un altro problema da considerare è l'indisponibilità di JS. Pensa all'incantesimo progressivo o al degrado aggraziato. Io suggerirei:

  • aggiungendo "più pulsante" per impostazione predefinita
  • aggiunta di regole di overflow per impostazione predefinita
  • pulsante nascosto e, se necessario, modifiche CSS in JS dopo aver confrontato element.scrollHeight con element.clientHeight

1

Ecco un violino per determinare se un elemento è stato traboccato usando un div wrapper con overflow: hidden e JQuery height () per misurare la differenza tra il wrapper e un div contenuto interno.

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

Fonte: Frameworks ed estensioni su jsfiddle.net


1

Questa è la soluzione jQuery che ha funzionato per me. clientWidthecc. non ha funzionato.

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

Se questo non funziona, assicurati che il genitore degli elementi abbia la larghezza desiderata (personalmente, ho dovuto usarlo parent().parent()). positionÈ relativo al genitore. Ho anche incluso extra_widthperché i miei elementi ("tag") contengono immagini che impiegano poco tempo per caricare, ma durante la chiamata di funzione hanno larghezza zero, rovinando il calcolo. Per aggirare quello, uso il seguente codice chiamante:

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

Spero che questo ti aiuti.


0
setTimeout(function(){
    isOverflowed(element)           
},500)

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

Questo ha funzionato per me. Grazie.


3
In che cosa differisce dalla risposta di Micnic?
attentnow1,

0

L'alternativa jquery alla risposta è usare il tasto [0] per accedere all'elemento raw come questo:

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

0

Ho esteso Element per motivi di incapsulamento. Dalla risposta micnic.

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

Usalo in questo modo

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

    if(elementInQuestion.isOverflowing()){
        // do something
    }
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.