Intersection observer rootBound gives incorrect value - javascript

I have a scroll container where children are scrolling in vertical direction. It has many small elements. The height of my scroll container is 100vh. My task is to observe them as soon as they reach 100px below top border(which is top of viewport in my case).
To achieve this I am creating an intersection observer on my scroll container element with rootmargin as -100px 0px 0px 0px.
I am observing on threshold 1.
In the intersection observer callback I am checking: entry.intersectionRect.top === entry.rootBound.top. This ensures that I am checking only topmost element.
All these operations are happening as expected but with one problem: intersection is not being observed 100px below top, but 81px below top. I confirmed this when I checked that in callback, value of entry.rootBound.top is 81px.
I suppose this should not be the case, the rootBound should have top similar to top margin that I gave in constructor option.
Very new to intersection observer and I want to use it in my project, but cannot do so with inconsistencies.

The only possible solution that seemed to be working correctly to me is to put an intersection observer on whole viewport, but pass a top margin of 10px(could be any value). Then observe that when the page loads, we would get a rootBounds value and that could indicate what is rootBounds.top. From there we could infer what is the device pixel ratio(givenMargin/rootBounds.top). Then we can simply unobserve that Infinite intersection observer.
This works generic for any browser, without worrying about to check which browser are we working on. Or we could check for browser and it's version and then import this kind of utility in our code.

Related

Can I trigger an animation when an element reaches half way in the viewport?

(JavaScript)
I can see that it is possible to trigger an animation using an IntersectionObserver when an element enters and leaves the viewport - but is there a way to trigger an animation when an element reaches half way in the view port?
you can use something like
new IntersectionObserver(yourAnimation, {rootMargin: "0px 0px -50% 0px"})
your element will be intersecting when it enters the top half of the viewport. basically adding a minus margin of half its height to the bottom edge of your root (here viewport)
You can use
if(elment.offsetLeft==window.offsetWidth) {startAnimation()}
// or element.offsetTop and window.offsetHeight
//you should write the startAnimation function, it not a built-in function

Intersection Observation continues when intersectionRatio is 1

Want to get some perspective on the Intersection Observer API.
For simplicity, I have a div element (Square 500px x 500px) that will rotate based on the user's scroll position. This is obtained by entry.boundingClientRect.top.
However, once the intersectionRatio reaches 1 (the element is in full view of the window), the square will stop rotating until it begins to fall outside of the viewport.
The threshold of the observer is set to an array from [0-100] and I understand once the element is in full view, the observer's job is more or less done but I want the rotation to still occur as the user scrolls down further and the square is still in view.
Some workarounds I found..
Div container with 100vh
Square height to be a percentage and offset the rootMargin within observer options.
Is it possible for the observer to still work when it is fully in view?
Would like to hear other approaches!

Can Intersection observer be used to calculate/trigger at specific offset top of target?

TL,DR:
I don't care how much of the target container is visible, I just want to know when the target container reaches a specific offset from top of the viewport (window). Should I stick with the good old scroll event or can this be done with Intersection observer?
Long story:
For a project I need to create a vertical scrolling parallax effect (as seen on this page, when viewed on large screens).
The parallax animation needs to detect when the target container reaches a specific offset from top of the viewport. And it needs to know the scroll direction.
I've found this question that explains how the visibilty percentage can be used to determine the scoll direction, which solves my 2nd problem.
So my question is: Can I use Intersection observer to trigger a callback when my target container reaches a specific offset from top of the viewport?
In pseudo-code, I'd need something like this:
var observer = new IntersectionObserver(offsetReached, {root: null});
function offsetReached(entries, observer) {
entries.forEach(entry => {
if (entry.offsetFromTop == '200px') {
entry.target.classList.add('container--fixed');
}
});
}
observer.observe('.container');
Intersectionobserver's purpose is to detect when a portion of element becomes visible, if you want to watch for offSetthe best option is to use the old fashioned scroll event and getBoundingClientRect() on the element you need to watch on.
Use the rootMargin option on the IntersectionObserver:
var observer = new IntersectionObserver(offsetReached, {rootMargin: '-200px'});
Each side of the rectangle represented by rootMargin is added to the corresponding side in the root element's bounding box before the intersection test is performed. (MDN Web Docs: Intersection)Observer.rootMargin)

Force element to scroll when it is slightly off screen

I need an element to scroll into the screen when it is partially out of it. I already have a function that is detecting whether or not it is within the viewport, but I would like to bring the element completely into the viewport using its size. Think of it as a square element which is half way in the viewport, I would like to scroll in a way that will bring that element completely in.
This may be off to the side or above or beneath the current viewport. How do I scroll the element into the viewport when it is detected to be out?
Here is the current code:
const $target = $(evt.target) // this is the current target which will be tested whether or not is outside of the viewport
if (isOutsideOfViewport($target)) {
$target.scrollToBringTargetCompletelyToViewport() // how to make something like this work?
}
Edit: to show in more details what I am trying to do, I have drawn the following diagram.
As you can see, the target is slightly outside of the viewport. The objective is to bring the target completely in the viewport.
Before:
After:
This would happen no matter where the target is on the screen, I just want to scroll just enough for it to be completely within the viewport.

When is Element.getBoundingClientRect guaranteed to be updated / accurate?

I am working on some code that uses Element.getBoundingClientRect (gBCR), coupled with inline style updates, to perform calculation. This is not for a general website and I am not concerned or interested in if there are "better CSS ways" of doing this task.
The JavaScript is run synchronously and performs these steps:
The parent's gBCR is fetched
Calculations are performed and;
A child element of the parent has inline CSS styles (eg. size and margins) updated
The parent's gBCR is fetched again
Am I guaranteed that the computed client bounds will reflect the new bounding rectangle of the parent at step 4?
If not guaranteed by a specification, is this "guaranteed" by modern1 browser implementations? If "mostly guaranteed", what notable exceptions are there?
Elements are not being added to or removed from the DOM and the elements being modified are direct children of the parent node; if such restrictions / information is relevant.
1"Modern": UIWebView (iOS 6+), WebView (Android 2+), and the usual Chrome/WebKit, FF, IE9+ suspects - including mobile versions.
I'm just stuck at gBCR unreliability on ios8.4.1/Safari8.0.
Prepare a large div on top of body (gBCR is 0) and scroll to bottom (gBCR is negative). Resize the div into 1x1 then window.scrollY automatically goes 0. gBCR should also be 0 but still stay negative value. With setTimeout, 200ms later, you can confirm the right value 0.
Old question, still the problem puzzled me and in my searches I had tumbled on this question. It might help others.
The best guarantee that I could find to make getBoundingClientRect() work reliably is to force a refresh at the top of the window, calculate the positions, and then go back wherever the user was.
Code would look something like:
scroll_pos = document.documentElement.scrollTop // save current position
window.scrollTo(0, 0); // go up
v_align = parseInt(el.getBoundingClientRect().top) // example of gBCR for vert.alignment
//... whatever other code you might need
window.scrollTo(0, scroll_pos); // get back to the starting position
Usually the operation is lightning fast, so the user should not notice it.

Categories

Resources