Vasiliy
Vasiliy

Reputation: 16228

element.getBoundingClientRect is inconsistent with window.innerHeight

I try to find out whether an element is partially visible at the bottom of viewport using the following code:

var child = document.getElementsByClassName('className')[0];
var top = child.getBoundingClientRect().top;
var bottom = child.getBoundingClientRect().bottom;
var partiallyVisibleBottom = top > 0 && bottom > window.innerHeight;

It doesn't work properly.

When I scroll such that the element of interest is only partially visible and observe the variables, I see that bottom is 900 while window.innerHeight is 1000. However, since the bottom of of the element is truncated, I'd expect this to be true: bottom > window.innerHeight.

What am I doing wrong?

Not sure it's relevant, but this code runs inside Android WebView.

Upvotes: 1

Views: 1474

Answers (2)

Vasiliy
Vasiliy

Reputation: 16228

Eventually I found out that the problem was with the logic that identified the "child" span. Turned out that there were several spans having the same class name (bug), which caused this unexpected result.

Upvotes: 0

pid
pid

Reputation: 11597

The comment cleared up a lot :-D With your new input this is something that may be helpful. Here, we use some trickery to get things done. Take notice of:

  • pure JS, no jQuery (but it will be even easier with jQuery, so it's your call);
  • see how the event target is got, this is for maximum browser cross-compatibility -- without this you'll leave some browsers behind;
  • the filter for "span1|span2|span3" is necessary because the user could very well click one pixel away from the actual span;
  • how the boolean partial is computed and stored for later use;
  • the id of the span is known;
  • the event handler is attached to div.container, not the spans (event bubbling is leveraged);
  • the use of CSS overflow-y: scroll to enable the vertical scrollbar only;
  • the outer div (container) may be the whole window... or not!

I hope this inspires you on how to do it in your case, I guess you cannot use this code directly, you'll have to pick from the above list what you need...

document.getElementById("container").onclick = (ev) => {
  var container, target, crect, trect, partial;

  ev = ev || window.event;
  target = ev.target || ev.srcElement;

  if ("span1|span2|span3".indexOf(target.id) !== -1) // only if a known element was actually clicked!
  {
    container = document.getElementById("container");
    crect = container.getBoundingClientRect();
    trect = target.getBoundingClientRect();

    partial = trect.top < crect.top || trect.bottom > crect.bottom;

    document.getElementById("status").innerText = 
      "target: " + target.id + " partial: " + partial;
  }
};
<pre id="status">STATUS</pre>
<div id="container" style="border: 1px solid #000; height: 100px; overflow-y: scroll;">
  <span id="span1" style="background-color: #f00;">This is the first span. This is the first span. This is the first span. This is the first span. This is the first span. This is the first span. This is the first span. This is the first span. This is the first span. This is the first span. This is the first span. This is the first span. This is the first span. This is the first span. This is the first span.</span>
  <span id="span2" style="background-color: #0f0;">This is the second span. This is the second span. This is the second span. This is the second span. This is the second span. This is the second span. This is the second span. This is the second span. This is the second span. This is the second span. This is the second span. This is the second span. This is the second span. This is the second span. This is the second span.</span>
  <span id="span3" style="background-color: #00f;">This is the third span. This is the third span. This is the third span. This is the third span. This is the third span. This is the third span. This is the third span. This is the third span. This is the third span. This is the third span. This is the third span. This is the third span. This is the third span. This is the third span. This is the third span.</span>
</div>

Upvotes: 1

Related Questions