132 votes

Comment vérifier si un élément est réellement visible avec JavaScript ?

En JavaScript, comment vérifier si un élément est réellement visible ?

Je ne veux pas seulement dire vérifier le visibility y display attributs. Je veux dire, vérifier que l'élément n'est pas

  • visibility: hidden o display: none
  • sous un autre élément
  • a défilé sur le bord de l'écran

Pour des raisons techniques, je ne peux pas inclure de scripts. Je peux cependant utiliser Prototype car il est déjà sur la page.

0 votes

Je ne voudrais pas vous rediriger vers jQuery (comme on le fait souvent), mais cette discussion sur le moment où les éléments sont vraiment visibles est très perspicace. Et comme jQuery 1.3.2 c'est plus de problème .

0 votes

Cela résout la première et la troisième partie, mais qu'en est-il de la deuxième ? Comment savoir s'il se trouve sous un autre élément ? De plus, pour des raisons techniques, je ne peux pas utiliser jQuery, ni aucun autre include, bien que Prototype soit déjà disponible.

0 votes

Pouvez-vous nous parler des problèmes techniques qui vous empêchent d'inclure les bibliothèques ? J'ai lu le même problème dans plusieurs cas, mais je ne vois pas de scénario pertinent (dans les documents XHTML, par exemple).

106voto

Christophe Eblé Points 4606

Pour le point 2.

Je vois que personne n'a suggéré d'utiliser document.elementFromPoint(x,y) Pour moi, c'est le moyen le plus rapide de tester si un élément est imbriqué ou caché par un autre. Vous pouvez passer les offsets de l'élément ciblé à la fonction.

Voici la page de test du PPK sur elementFromPoint .

Desde La documentation de MDN :

El elementFromPoint() disponible sur les objets Document et ShadowRoot, renvoie l'élément le plus haut aux coordonnées spécifiées (par rapport à la fenêtre d'affichage).

0 votes

N'est-ce pas une solution uniquement IE ?

0 votes

@e-satis : Cela fonctionne dans Firefox pour moi. Cela ne fonctionne pas dans Opera.

6 votes

Qu'en est-il de la transparence des éléments ? Je suppose que vous pouvez vous retrouver dans la situation où elementFromPoint() dit que cet élément est complètement recouvert par un autre (et que vous le traitez comme invisible) mais que l'utilisateur peut le voir.

42voto

Tobias Points 1064

Je ne sais pas dans quelle mesure cela est pris en charge par les navigateurs plus anciens ou moins modernes, mais j'utilise quelque chose comme ceci (sans avoir besoin de bibliothèques) :

function visible(element) {
  if (element.offsetWidth === 0 || element.offsetHeight === 0) return false;
  var height = document.documentElement.clientHeight,
      rects = element.getClientRects(),
      on_top = function(r) {
        var x = (r.left + r.right)/2, y = (r.top + r.bottom)/2;
        return document.elementFromPoint(x, y) === element;
      };
  for (var i = 0, l = rects.length; i < l; i++) {
    var r = rects[i],
        in_viewport = r.top > 0 ? r.top <= height : (r.bottom > 0 && r.bottom <= height);
    if (in_viewport && on_top(r)) return true;
  }
  return false;
}

Il vérifie que l'élément a une surface > 0 et ensuite il vérifie si une partie de l'élément est dans le viewport et qu'il n'est pas caché "sous" un autre élément (en fait je ne vérifie que sur un seul point au centre de l'élément, donc ce n'est pas assuré à 100% -- mais vous pourriez juste modifier le script pour itérer sur tous les points de l'élément, si vous en avez vraiment besoin...).

Mise à jour

Modifié la fonction on_top qui vérifie chaque pixel :

on_top = function(r) {
  for (var x = Math.floor(r.left), x_max = Math.ceil(r.right); x <= x_max; x++)
  for (var y = Math.floor(r.top), y_max = Math.ceil(r.bottom); y <= y_max; y++) {
    if (document.elementFromPoint(x, y) === element) return true;
  }
  return false;
};

Je ne sais pas pour les performances :)

1 votes

Qu'est-ce que les paramètres element.offsetWidth/offsetHeight essaient de trouver ? Ils semblent toujours renvoyer 0 dans Chrome. Et le paramètre document.documentElement.clientHeight récupère la hauteur de l'élément ; ne devrait-il pas être document.body.clientHeight ?

0 votes

Pour la hauteur visible de la fenêtre, cela semble fonctionner sur tous les navigateurs (même les anciens IE) : height = window.innerHeight?window.innerHeight:document.documentEleme‌​nt.clientHeight;

1 votes

Que se passe-t-il si un élément est complètement recouvert par un autre (dans le cadre de cette approche) mais que l'élément qui le recouvre présente une certaine transparence ? Ainsi, l'élément situé en dessous est visible pour l'utilisateur mais traité comme non visible par la méthode.

7voto

Jason Tillery Points 41

Comme l'a souligné jkl, vérifier la visibilité ou l'affichage de l'élément n'est pas suffisant. Vous devez vérifier ses ancêtres. Selenium le fait lorsqu'il vérifie la visibilité d'un élément.

Vérifiez la méthode Selenium.prototype.isVisible dans le fichier selenium-api.js.

http://svn.openqa.org/svn/selenium-on-rails/selenium-on-rails/selenium-core/scripts/selenium-api.js

0 votes

Merci. Le code est maintenant déplacé vers : code.google.com/p/selenium/source/browse/javascript/

1 votes

0 votes

Ce n'est pas vrai, Selenium vérifie isVisible seulement en vérifiant les propriétés css 'display' et 'visibility', dans le lien que vous partagez github.com/SeleniumHQ/selenium/blob/master/javascript/ Selenium.prototype.isVisible ... return (visibility != "hidden" && _isDisplayed) ;

4voto

Christophe Eblé Points 4606

Question intéressante.

Ce serait mon approche.

  1. Vérifiez d'abord que element.style.visibility !== 'hidden' && element.style.display !== 'none'.
  2. Ensuite, je teste avec document.elementFromPoint(element.offsetLeft, element.offsetTop) si l'élément renvoyé est celui que j'attends, ce qui est délicat pour détecter si un élément en recouvre complètement un autre.
  3. Enfin, vérifiez si offsetTop et offsetLeft sont situés dans le viewport en tenant compte des décalages de défilement.

J'espère que cela vous aidera.

0 votes

Pourriez-vous expliquer document.elementFromPoint plus en détail ?

0 votes

Voici le résumé du MDC de Mozilla : Renvoie l'élément du document dont la méthode elementFromPoint est appelée, qui est l'élément le plus haut situé sous le point donné. Le point est spécifié par des coordonnées, en pixels CSS, par rapport au point le plus haut à gauche de la fenêtre ou du cadre contenant le document.

2voto

yaanno Points 221

Prototype Bibliothèque d'éléments est l'une des bibliothèques de requêtes les plus puissantes en termes de méthodes. Je vous recommande de consulter l'API.

Quelques conseils :

  1. Le contrôle de la visibilité peut être fastidieux, mais vous pouvez utiliser la fonction Element.getStyle() et Element.visible() combinées dans une fonction personnalisée. Avec getStyle() vous pouvez vérifier le style calculé actuel.

  2. Je ne sais pas exactement ce que vous voulez dire par "en dessous" :) Si vous voulez dire qu'il a un ancêtre spécifique, par exemple, un div wrapper, vous pouvez utiliser Element.up(cssRule) :

    var child = $("myparagraph");
    if(!child.up("mywrapper")){
      // I lost my mom!
    }
    else {
      // I found my mom!
    }

    Si vous souhaitez vérifier les frères et sœurs de l'élément enfant, vous pouvez également le faire :

    var child = $("myparagraph");
    if(!child.previous("mywrapper")){
      // I lost my bro!
    } 
    else {
      // I found my bro!
    }
  3. Encore une fois, Element lib peut vous aider si je comprends bien ce que vous voulez dire :) Vous pouvez vérifier l'actuel dimensions de la fenêtre de visualisation y el le décalage de votre élément afin que vous puissiez calculer si votre élément est "hors écran".

Bonne chance !

J'ai collé un cas de test pour prototypejs à http://gist.github.com/117125 . Il semble que dans votre cas, nous ne pouvons tout simplement pas avoir confiance en getStyle() du tout. Pour maximiser la fiabilité de la fonction isMyElementReallyVisible, vous devez combiner les éléments suivants :

  • Vérification du style de calcul (dojo a une belle fonction mise en œuvre que vous pouvez emprunter)
  • Vérification du décalage du port de vue (méthode native du prototype)
  • Vérification du z-index pour le problème du "dessous" (sous Internet Explorer, cela peut être buggé)

0 votes

Je crois que j'ai mal compris la question. Vous voulez être sûr que votre élément est visible dans la fenêtre d'affichage quoi qu'il arrive, n'est-ce pas ?

0 votes

1 et 3 sont bien. Vous avez mal compris le 2. J'ai quelques éléments qui sont libres de se déplacer sur l'écran. L'élément en question se trouverait sous un autre élément si, par exemple, un utilisateur faisait glisser une boîte à outils au-dessus de lui.

0 votes

Pour clarifier mon dernier point, la boîte à outils serait un div à l'intérieur du corps, tandis que l'élément pourrait se trouver à quelques niveaux de profondeur.

Prograide.com

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.

Powered by:

X