Existe-t-il un moyen efficace de savoir si un élément DOM (dans un document HTML) est actuellement visible (apparaît dans la fenêtre d'affichage )?
(La question concerne Firefox)
Existe-t-il un moyen efficace de savoir si un élément DOM (dans un document HTML) est actuellement visible (apparaît dans la fenêtre d'affichage )?
(La question concerne Firefox)
Maintenant, la plupart des navigateurs soutien getBoundingClientRect méthode, qui est devenu la meilleure pratique. À l'aide d'une vieille réponse est très lent, pas précis, et dispose de plusieurs bugs.
IE8 prend en charge entièrement, IE7 n'est pas parfait, mais il fonctionne mieux que l'ancien réponse.
La solution choisie comme correcte est presque jamais précis. Vous pouvez lire plus au sujet de ses bugs.
function isElementInViewport (el) {
//special bonus for those using jQuery
if (el instanceof jQuery) {
el = el[0];
}
var rect = el.getBoundingClientRect();
return (
rect.top >= 0 &&
rect.left >= 0 &&
rect.bottom <= (window.innerHeight || document.documentElement.clientHeight) && /*or $(window).height() */
rect.right <= (window.innerWidth || document.documentElement.clientWidth) /*or $(window).width() */
);
}
Vous pouvez être sûr que la fonction donnée ci-dessus renvoie la réponse correcte au moment de l'instant quand on l'appelle, mais ce que sur le suivi de l'élément de la visibilité d'un événement?
Placez le code suivant au bas de votre <body>
balise:
function callback () {
//your code here, e.g. console.log('is visible now');
}
function fireIfElementVisible (el, callback) {
return function () {
if ( isElementInViewport(el) ) {
callback();
}
}
}
var handler = fireIfElementVisible (el, callback);
//jQuery
$(window).on('DOMContentLoaded load resize scroll', handler);
/* //non-jQuery
if (window.addEventListener) {
addEventListener('DOMContentLoaded', handler, false);
addEventListener('load', handler, false);
addEventListener('scroll', handler, false);
addEventListener('resize', handler, false);
} else if (window.attachEvent) {
attachEvent('onDOMContentLoaded', handler); // IE9+ :(
attachEvent('onload', handler);
attachEvent('onscroll', handler);
attachEvent('onresize', handler);
}
*/
Si vous n'avez aucune DOM modifications, ils peuvent changer votre élément de visibilité de cours.
Des lignes directrices et des écueils les plus courants:
Peut-être vous avez besoin de suivre la page de zoom / appareil mobile pincée? jQuery doit gérer le zoom/pincement de la croix-navigateur, sinon la première ou de la deuxième lien devrait vous aider.
Si vous modifier le DOM, il peut affecter l'élément de visibilité. Vous devez prendre le contrôle et appelez - handler()
manuellement. Malheureusement, nous n'avons pas de croix-navigateur onrepaint
événement. Sur l'autre main qui nous permet de faire des optimisations et d'effectuer des re-vérifier uniquement sur les DOM modifications qui peuvent changer l'élément de visibilité.
Ne jamais utiliser à l'intérieur de jQuery $(document).ready() , car il n'y a aucune garantie CSS a été appliquée en ce moment. Votre code peut travailler localement avec votre CSS sur le disque dur, mais une fois sur le serveur distant, il va échouer.
Après l' DOMContentLoaded
est tiré, les styles sont appliqués, mais les images ne sont pas encore chargés. Donc, il convient d'ajouter window.onload
écouteur d'événement.
On ne peut pas attraper de zoom/pincée événement encore.
Le dernier recours pourrait être le code suivant:
/* TODO: this looks like a very bad code */
setInterval(handler, 600);
Vous pouvez utiliser la fonctionnalité impressionnante pageVisibiliy API HTML5 si vous vous souciez si l'onglet de votre page web est active et visible.
TODO: cette méthode ne permet pas de gérer deux situations:
z-index
overflow-scroll
dans l'élément du conteneurDans ce cas, vous devriez aller et code quelque chose de plus...
Mise à jour: le Temps a passé et ont donc nos navigateurs. Cette technique n'est plus recommandé et vous devez l'utiliser @Dan la solution ci-dessous (http://stackoverflow.com/a/7557433/5628) si vous n'avez pas besoin de soutenir IE<7.
Solution originale (aujourd'hui obsolète):
Cela permettra de vérifier si l'élément est entièrement visible dans la fenêtre actuelle:
function elementInViewport(el) {
var top = el.offsetTop;
var left = el.offsetLeft;
var width = el.offsetWidth;
var height = el.offsetHeight;
while(el.offsetParent) {
el = el.offsetParent;
top += el.offsetTop;
left += el.offsetLeft;
}
return (
top >= window.pageYOffset &&
left >= window.pageXOffset &&
(top + height) <= (window.pageYOffset + window.innerHeight) &&
(left + width) <= (window.pageXOffset + window.innerWidth)
);
}
Vous pouvez modifier ceci tout simplement afin de déterminer si une partie quelconque de l'élément est visible dans la fenêtre:
function elementInViewport2(el) {
var top = el.offsetTop;
var left = el.offsetLeft;
var width = el.offsetWidth;
var height = el.offsetHeight;
while(el.offsetParent) {
el = el.offsetParent;
top += el.offsetTop;
left += el.offsetLeft;
}
return (
top < (window.pageYOffset + window.innerHeight) &&
left < (window.pageXOffset + window.innerWidth) &&
(top + height) > window.pageYOffset &&
(left + width) > window.pageXOffset
);
}
Il ya quelques problèmes avec la réponse fournie par Dan qui pourrait le rendre inapte à l'approche de certaines situations. Certaines de ces questions sont fait remarquer dans sa réponse, vers le bas, que son code va donner de faux positifs pour les éléments qui sont:
clip
de la propriétéCes limites sont illustrées dans les résultats d'un test simple:
isElementVisible()
Voici une solution à ces problèmes, avec le résultat du test ci-dessous et une explication de certaines parties du code.
function isElementVisible(el) {
var eap,
rect = el.getBoundingClientRect(),
docEl = document.documentElement,
vWidth = window.innerWidth || docEl.clientWidth,
vHeight = window.innerHeight || docEl.clientHeight,
efp = function (x, y) { return document.elementFromPoint(x, y) },
contains = "contains" in el ? "contains" : "compareDocumentPosition",
has = contains == "contains" ? 1 : 0x14;
// Return false if it's not in the viewport
if (rect.right < 0 || rect.bottom < 0
|| rect.left > vWidth || rect.top > vHeight)
return false;
// Return true if any of its four corners are visible
return (
(eap = efp(rect.left, rect.top)) == el || el[contains](eap) == has
|| (eap = efp(rect.right, rect.top)) == el || el[contains](eap) == has
|| (eap = efp(rect.right, rect.bottom)) == el || el[contains](eap) == has
|| (eap = efp(rect.left, rect.bottom)) == el || el[contains](eap) == has
);
}
Test de passage: http://jsfiddle.net/AndyE/cAY8c/3/
Et le résultat:
Cette méthode n'est pas sans ses propres limites, cependant. Par exemple, un élément testé avec une baisse de z-index supérieur à un autre élément au même endroit serait identifié comme caché, même si l'élément n'a pas de cacher une partie. Cependant, cette méthode a ses utilise, dans certains cas, que Dan solution ne permet pas de couvrir.
Les deux element.getBoundingClientRect()
et document.elementFromPoint()
font partie de la CSSOM de Travail Projet de spécification et sont pris en charge dans au moins IE 6 et, plus tard, et la plupart des navigateurs de bureau pour un long moment (quoique, pas parfaitement). Voir Quirksmode sur ces fonctions pour plus d'informations.
contains()
(vieux IE) et compareDocumentPosition()
sont utilisés pour voir si l'élément retourné par document.elementFromPoint()
est un nœud enfant de l'élément que nous sommes en train de tester pour la visibilité. Cela fait juste plus robuste.
Si vous voulez tester le plus de points autour de l'élément de visibilité―c'est à dire, pour s'assurer que l'élément n'est pas couvert par plus de, disons, 50%―ça ne serait pas prendre beaucoup pour régler la dernière partie de la réponse. Cependant, être conscient qu'il serait probablement très lent si vous avez coché chaque pixel pour s'assurer qu'il a été de 100% du visible.
J'ai essayé la réponse de Dan, mais l'algèbre utilisée pour déterminer les limites est incorrecte. La réponse de ryanve est plus proche, mais l'élément testé doit être à l'intérieur de la fenêtre d'au moins 1 pixel, alors essayez cette fonction:
function isElementInViewport(el) {
var rect = el.getBoundingClientRect();
return rect.bottom > 0 &&
rect.right > 0 &&
rect.left < (window.innerWidth || document. documentElement.clientWidth) /*or $(window).width() */ &&
rect.top < (window.innerHeight || document. documentElement.clientHeight) /*or $(window).height() */;
}
Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.