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?
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
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/ .
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.
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.
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.
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>
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.
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);
});
Une autre question à prendre en compte est l’indisponibilité de JS. Pensez à l'enchantement progressif ou à la dégradation gracieuse. Je voudrais suggerer:
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 ..
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){
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
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.