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


154

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

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

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

Réponses:


86

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 est l'utilisation de 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;
}
<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>

Le code et l'exemple que vous pouvez trouver sur http://dabblet.com/gist/2462915

Et une explication que vous pouvez trouver ici: http://lea.verou.me/2012/04/background-attachment-local/ .


1
Bonne idée mais dans votre exemple le fond (ombre) serait derrière le texte!
DreamTeK

Excellent truc, mais dans Chrome, il ne montre qu'une ombre statique en bas, il ne disparaît jamais et l'ombre supérieure ne s'affiche jamais
Jared

214

L'élément peut être survolé verticalement, horizontalement ou les deux. Cette fonction vous renverra une valeur booléenne si l'élément DOM est survolé:

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

Exemple ES6:

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

41
Excellente solution! Voici une variante de jQuery (à utiliser avec $("#element").overflown()):$.fn.overflown=function(){var e=this[0];return e.scrollHeight>e.clientHeight||e.scrollWidth>e.clientWidth;}
Sygmoral

@micnic salut, j'utilise ionic2 et j'essaie de faire la même chose ... mais la fonction retourne toujours vrai ... y a-t-il une façon différente de faire les choses dans angular 2
Yasir

@DavidBracoly, cette fonction est pour l'API DOM pure, je n'ai pas d'expérience avec Ionic / Angular, je suppose que vous devriez obtenir l'élément DOM original et utiliser cette fonction
micnic

3
Uniquement pour Firefox: element.addEventListener ("overflow", () => log( "overflow" ), false);Référence: événement de débordement
Reza

18

La comparaison element.scrollHeightavec element.clientHeightdevrait faire la tâche.

Vous trouverez ci-dessous les images de MDN expliquant Element.scrollHeight et Element.clientHeight.

Hauteur de défilement

Hauteur du client


2
Ouais, mais selon quirksmode, cela fonctionne pour la plupart - et est beaucoup plus simple que les autres solutions publiées.
Bergi

@Harry: Il est pris en charge dans tous les navigateurs actuels (au moins ceux de bureau), donc peu importe que ce soit formellement non standard.
Marat Tanalin

1
Ici, ces propriétés ont toujours les mêmes valeurs.
koppor

7

J'ai fait un codepen en plusieurs parties démontrant les réponses ci-dessus (par exemple en utilisant le débordement caché et la hauteur) mais aussi comment vous étendre / réduire les éléments débordés

Exemple 1: https://codepen.io/Kagerjay/pen/rraKLB (Véritable exemple simple, pas de javascript, juste pour couper les éléments débordés)

Exemple 2: https://codepen.io/Kagerjay/pen/LBErJL (gestionnaire d'événements unique show more / showless sur les éléments débordés)

Exemple 3: https://codepen.io/Kagerjay/pen/MBYBoJ (Gestionnaire multi-événements sur beaucoup afficher plus / afficher moins sur les éléments débordés)

J'ai également joint l'exemple 3 ci-dessous , j'utilise Jade / Pug, donc ça pourrait être un peu verbeux. Je suggère de vérifier les codepens que j'ai simplifiés à 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>


4

Quelque chose comme ceci: http://jsfiddle.net/Skooljester/jWRRA/1/ fonctionne? Il vérifie simplement la hauteur du contenu et la compare à la hauteur du conteneur. Si c'est plus grand que vous pouvez mettre dans le code pour ajouter un bouton "Afficher plus".

Mise à jour: Ajout du code pour créer un bouton «Afficher plus» en haut du conteneur.


3

Si vous utilisez jQuery, vous pouvez essayer une astuce: créer un div externe avec overflow: hiddenet un div interne avec du contenu. Ensuite, utilisez la .height()fonction 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.


1

utilisez js pour vérifier si l'enfant offsetHeightest plus que les parents .. si c'est le cas, faites déborder les parents scroll/hidden/autoselon ce que vous voulez et aussi display:blocksur le plus de div ..


1

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

// 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, il vous dira si ses limites sont entièrement à l'intérieur d'un conteneur, et sera par défaut le parent offset de l'élément si aucun conteneur explicite n'est fourni. Il utilise


1

Un autre problème à prendre en compte est l'indisponibilité de JS. Pensez à l'enchantement progressif ou à la dégradation gracieuse. Je voudrais suggerer:

  • ajout d'un "bouton plus" par défaut
  • ajout de règles de débordement par défaut
  • bouton masquant et si nécessaire modifications CSS dans JS après comparaison de element.scrollHeight à element.clientHeight

1

Voici un violon pour déterminer si un élément a été débordé à l'aide d'un div wrapper avec débordement: hidden et JQuery height () pour mesurer la différence entre le wrapper et un 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

C'est la solution jQuery qui a fonctionné pour moi. clientWidthetc. 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, j'ai dû utiliser parent().parent()). positionEst relatif au parent. J'ai également inclus extra_widthparce que mes éléments ("balises") contiennent des images qui prennent peu de temps à charge, mais pendant l'appel de fonction, ils ont une largeur nulle, ce qui gâche le calcul. Pour contourner cela, 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.


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


3
En quoi est-ce différent de la réponse de micnic?
Attentionnow1

0

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

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

0

J'ai étendu Element pour des raisons d'encapsulation. De la réponse 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;
}

Utilisez-le comme ça

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

    if(elementInQuestion.isOverflowing()){
        // do something
    }
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.