web-dev-qa-db-fra.com

Vérifier si le contenu d'un élément déborde?

Quel est le moyen le plus simple de détecter si un élément a été débordé?

Mon cas d'utilisation est, je veux limiter une zone de contenu à une hauteur de 300px. Si le contenu interne est plus grand que cela, je le coupe avec un débordement. Mais s'il est débordé, je souhaite afficher un bouton "Plus", mais sinon, je ne souhaite pas afficher ce bouton.

Existe-t-il un moyen simple de détecter les débordements ou existe-t-il une meilleure méthode?

92
Harry

Cette fonction vous renverra une valeur booléenne si l'élément DOM est débordé:

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

L'élément peut déborder verticalement ou horizontalement ou les deux

136
micnic

Si vous souhaitez afficher uniquement un identifiant pour plus de contenu, vous pouvez le faire avec du CSS pur. J'utilise des ombres de défilement pures pour cela. L'astuce consiste à utiliser background-attachment: local;. Votre css ressemble à ceci:

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

Le code et un exemple que vous pouvez trouver sur http://dabblet.com/Gist/2462915

Et une explication, vous trouverez ici: http://lea.verou.me/2012/04/background-attachment-local/ .

30
RWAM

La comparaison element.scrollHeight à element.clientHeight devrait s’acquitter de cette tâche.

Ci-dessous, les images de MDN expliquant Element.scrollHeight et Element.clientHeight.

 Scroll Height

 Client Height

9
Bergi

Est-ce que quelque chose comme ceci: http://jsfiddle.net/Skooljester/jWRRA/1/ fonctionne? Il vérifie simplement la hauteur du contenu et le compare à la hauteur du conteneur. S'il est supérieur à ce que vous pouvez insérer dans le code, un bouton "Afficher plus" sera ajouté.

Update: Ajout du code pour créer un bouton "Afficher plus" en haut du conteneur.

4
jezza-tan

Si vous utilisez jQuery, essayez une astuce: créez une division externe avec overflow: hidden et une division interne avec le contenu. Utilisez ensuite la fonction .height() pour vérifier si la hauteur de la div interne est supérieure à la hauteur de la div externe. Je ne suis pas sûr que cela fonctionnera, mais essayez-le.

3
TMS

J'ai créé un codepen en plusieurs parties illustrant les réponses ci-dessus (par exemple, en utilisant les débordements cachés et hauteur), mais également la manière dont vous développeriez/réduisez les éléments débordés.

Exemple 1: https://codepen.io/Kagerjay/pen/rraKLB (Exemple très simple, pas de javascript, il suffit de couper les éléments débordés)

Exemple 2: https://codepen.io/Kagerjay/pen/LBErJL (Un seul gestionnaire d'événements affiche plus/sans affichage sur les éléments débordés)

Exemple 3: https://codepen.io/Kagerjay/pen/MBYBoJ (gestionnaire d'événements multiples sur de nombreux show more/show moins sur les éléments débordés)

J'ai aussi ci-joint l'exemple 3 ci-dessous, j'utilise Jade/Pug donc ça pourrait être un peu bavard. Je suggère de vérifier les codepens que j'ai fait sa plus simple à saisir.

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

2
Vincent Tang

C'est la solution jQuery qui a fonctionné pour moi. clientWidth etc. n'a pas fonctionné.

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

Si cela ne fonctionne pas, assurez-vous que le parent des éléments a la largeur souhaitée (personnellement, je devais utiliser parent().parent()). position est relatif au parent. J'ai également inclus extra_width car mes éléments ("tags") contiennent des images qui prennent peu de temps pour charger, mais lors de l'appel de la fonction, ils ont une largeur nulle, ce qui gâche le calcul. Pour contourner ce problème, j'utilise le code d'appel suivant:

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

J'espère que cela t'aides.

1

Voici un moyen de déterminer si un élément a été saturé à l’aide d’un div de wrapper avec overflow: hidden et de hauteur JQuery () pour mesurer la différence entre le wrapper et une div de contenu interne.

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

Source:Frameworks & Extensions sur jsfiddle.net

1
user1295799

Une autre question à prendre en compte est l’indisponibilité de JS. Pensez à l'enchantement progressif ou à la dégradation gracieuse. Je voudrais suggerer:

  • ajout de "plus de boutons" par défaut
  • ajout de règles de débordement par défaut
  • masquer le bouton et si nécessaire les modifications CSS dans JS après avoir comparé element.scrollHeight à element.clientHeight 
1
MFix

utilisez js pour vérifier si la variable offsetHeight de l'enfant est supérieure à celle de ses parents .. si c'est le cas, faites déborder les parents scroll/hidden/auto comme vous le souhaitez et aussi display:block sur l'élément div plus .. 

1
Vivek Chandra

L'alternative jquery à la réponse consiste à utiliser la touche [0] pour accéder à l'élément brut tel que celui-ci:

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

Vous pouvez vérifier les limites relatives au parent décalé.

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

Si vous passez cet élément à un élément, il vous dira si ses limites se trouvent entièrement à l'intérieur d'un conteneur et par défaut au parent de l'élément décalé si aucun conteneur explicite n'est fourni. Il utilise

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

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

Cela a fonctionné pour moi. Je vous remercie.

0
Krunal