Sprawdź, czy zawartość elementu się przepełnia?

153

Jaki jest najłatwiejszy sposób wykrycia, czy element został przepełniony?

Mój przypadek użycia polega na tym, że chcę ograniczyć określone pole zawartości, aby miało wysokość 300 pikseli. Jeśli zawartość wewnętrzna jest wyższa, odcinam ją przelewem. Ale jeśli jest przepełniony, chcę pokazać przycisk „więcej”, ale jeśli nie, nie chcę pokazywać tego przycisku.

Czy istnieje łatwy sposób na wykrycie przepełnienia, czy też jest lepsza metoda?

Złupić
źródło

Odpowiedzi:

86

Jeśli chcesz wyświetlać tylko identyfikator dla większej ilości treści, możesz to zrobić za pomocą czystego CSS. Używam do tego czystych cieni przewijania. Sztuczka polega na użyciu background-attachment: local;. Twój CSS wygląda tak:

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

Kod i przykład można znaleźć na http://dabblet.com/gist/2462915

Wyjaśnienie można znaleźć tutaj: http://lea.verou.me/2012/04/background-attachment-local/ .

RWAM
źródło
1
Niezły pomysł, ale w twoim przykładzie tło (cień) byłoby za tekstem!
DreamTeK
Świetna sztuczka, jednak w Chrome pokazuje tylko statyczny cień na dole, nigdy nie znika, a górny cień nigdy się nie pojawia
Jared
214

Element może zostać przelany pionowo, poziomo lub w obu przypadkach. Ta funkcja zwróci wartość logiczną, jeśli element DOM jest przepełniony:

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

Przykład ES6:

const isOverflown = ({ clientWidth, clientHeight, scrollWidth, scrollHeight }) => {
    return scrollHeight > clientHeight || scrollWidth > clientWidth;
}
micnic
źródło
41
Świetne rozwiązanie! Oto wariant jQuery (do użycia z $("#element").overflown()):$.fn.overflown=function(){var e=this[0];return e.scrollHeight>e.clientHeight||e.scrollWidth>e.clientWidth;}
Sygmoral
@micnic cześć, używam ionic2 i próbuję zrobić to samo ... ale funkcja zawsze zwraca prawdę ... czy jest inny sposób robienia rzeczy w angular 2
Yasir
@DavidBracoly, ta funkcja jest przeznaczona dla czystego DOM API, nie mam doświadczenia z Ionic / Angular, myślę, że powinieneś zdobyć oryginalny element DOM i użyć tej funkcji
micnic
3
Tylko dla przeglądarki Firefox: element.addEventListener ("overflow", () => log( "overflow" ), false);Odniesienie: zdarzenie przepełnienia
Reza
18

Porównywanie element.scrollHeight do element.clientHeightpowinien wykonać zadanie.

Poniżej znajdują się obrazy z MDN wyjaśniające elementy Element.scrollHeight i Element.clientHeight.

Wysokość przewijania

Wysokość klienta

Bergi
źródło
2
Tak, ale zgodnie z quirksmode działa w większości - i jest znacznie prostszy niż inne opublikowane rozwiązania.
Bergi
@Harry: Jest obsługiwany we wszystkich obecnych przeglądarkach (przynajmniej komputerowych), więc nie ma znaczenia, że ​​formalnie jest niestandardowy.
Marat Tanalin
1
Tutaj te właściwości mają zawsze te same wartości.
koppor
7

Zrobiłem wieloczęściowy kodepen demonstrujący powyższe odpowiedzi (np. Używając ukrytego przepełnienia i wysokości), ale także tego, jak możesz rozwinąć / zwinąć przepełnione elementy

Przykład 1: https://codepen.io/Kagerjay/pen/rraKLB (Naprawdę prosty przykład, bez javascript, tylko po to, aby wyciąć przepełnione elementy)

Przykład 2: https://codepen.io/Kagerjay/pen/LBErJL (Obsługa pojedynczego zdarzenia pokazuje więcej / niewidoczne dla przepełnionych elementów)

Przykład 3: https://codepen.io/Kagerjay/pen/MBYBoJ (Obsługa wielu zdarzeń na wielu pokazuje więcej / pokazuje mniej na przepełnionych elementach)

Mam załączeniu przykład 3 poniżej, jak również , używam Jade / Pug więc to może być odrobinę rozwlekły. Proponuję zapoznać się z kodami, które ułatwiłem zrozumienie.

// 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
źródło
4

Czy coś takiego: http://jsfiddle.net/Skooljester/jWRRA/1/ działa? Po prostu sprawdza wysokość zawartości i porównuje ją z wysokością kontenera. Jeśli jest większy, niż możesz umieścić w kodzie, aby dołączyć przycisk „Pokaż więcej”.

Aktualizacja: dodano kod, aby utworzyć przycisk „Pokaż więcej” u góry kontenera.

ayyp
źródło
3

Jeśli używasz jQuery, możesz spróbować sztuczki: utwórz zewnętrzny element div z overflow: hiddeni wewnętrzny element div z zawartością. Następnie użyj .height()funkcji, aby sprawdzić, czy wysokość wewnętrznego elementu div jest większa niż wysokość zewnętrznego elementu div. Nie jestem pewien, czy to zadziała, ale spróbuj.

TMS
źródło
1

użyj js, aby sprawdzić, czy dziecko offsetHeightma więcej niż rodziców .. jeśli tak, spraw, aby rodzice przepełnili to, scroll/hidden/autoco chcesz, a także display:blockna więcej div ..

Vivek Chandra
źródło
1

Możesz sprawdzić granice względem elementu macierzystego odsunięcia.

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

Jeśli przekażesz to element, powie ci, czy jego granice są całkowicie wewnątrz kontenera i domyślnie przestawi element nadrzędny przesunięcia elementu, jeśli nie zostanie podany wyraźny kontener. To używa

Mike Samuel
źródło
1

Kolejną kwestią, którą należy rozważyć, jest niedostępność JS. Pomyśl o stopniowym zaklęciu lub wdzięcznej degradacji. Sugerowałbym:

  • dodanie „przycisku więcej” domyślnie
  • dodawanie reguł przepełnienia
  • przycisk ukrywania i ewentualnie modyfikacje CSS w JS po porównaniu element.scrollHeight z elementem.clientHeight
MFix
źródło
1

Oto skrzypce do określenia, czy element został przepełniony za pomocą opakowującego elementu div z przepełnieniem: hidden i JQuery height (), aby zmierzyć różnicę między opakowaniem a wewnętrznym elementem div zawartości.

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

Źródło: Framework i rozszerzenia na jsfiddle.net

user1295799
źródło
1

To jest rozwiązanie jQuery, które zadziałało dla mnie. clientWidthitp. nie działały.

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

Jeśli to nie zadziała, upewnij się, że element nadrzędny ma żądaną szerokość (osobiście musiałem użyć parent().parent()). positionJest względem elementu nadrzędnego. Uwzględniłem również, extra_widthponieważ moje elementy („tagi”) zawierają obrazy, których load, ale podczas wywołania funkcji mają zerową szerokość, co psuje obliczenia.Aby to obejść, używam następującego kodu wywołującego:

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

Mam nadzieję że to pomoże.

Dennis Golomazov
źródło
0
setTimeout(function(){
    isOverflowed(element)           
},500)

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

To zadziałało dla mnie. Dziękuję Ci.

Krunal
źródło
3
Czym to się różni od odpowiedzi Micnic?
ostrożność 1
0

Alternatywą dla odpowiedzi w jquery jest użycie klawisza [0] w celu uzyskania dostępu do surowego elementu, na przykład:

if ($('#elem')[0].scrollHeight > $('#elem')[0].clientHeight){
Antony
źródło
0

Rozszerzyłem Element ze względu na enkapsulację. Z micnic odpowiedzi.

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

Użyj tego w ten sposób

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

    if(elementInQuestion.isOverflowing()){
        // do something
    }
David Clews
źródło