I have a piece of code that adds a different css class to elements depending on whether they're scrolled into or out of the viewport from top or bottom.
It uses the Intersection Observer because it is supposed to handle large amounts of elements better than scroll
events.
However, I am facing two problems with this code:
This is odd because the IntersectionObserver should work fine on Safari and even mobile browsers on iOS.
You can find the code on jsFiddle or see the snippet here:
const config = {
// Add root here so rootBounds in entry object is not null
root: document,
// Margin to when element should take action
rootMargin: '-50px 0px',
// Callback will be fired 30 times during intersection
threshold: [...Array(30).keys()].map(x => x / 29)
};
let observer = new IntersectionObserver(function(entries, observer) {
entries.forEach((entry, index) => {
const element = entry.target;
// Get root element (document) coords
const rootTop = entry.rootBounds.top;
const rootBottom = entry.rootBounds.height;
// Get div coords
const topBound = entry.boundingClientRect.top - 50; // margin in config
const bottomBound = entry.boundingClientRect.bottom;
let className;
// Do calculations to get class names
if (topBound < rootTop && bottomBound < rootTop) {
className = "outview-top";
} else if (topBound > rootBottom) {
className = "outview-bottom";
} else if (topBound < rootBottom && bottomBound > rootBottom) {
className = "inview-bottom";
} else if (topBound < rootTop && bottomBound > rootTop) {
className = "inview-top";
}
element.setAttribute('data-view', className);
});
}, config);
const viewbox = document.querySelectorAll('.viewme');
viewbox.forEach(image => {
observer.observe(image);
});
body {
text-align: center;
}
.margins {
position: fixed;
top: 50px;
bottom: 50px;
border-top: 2px dashed;
border-bottom: 2px dashed;
z-index: 1;
left: 0;
width: 100%;
pointer-events: none;
}
.hi {
padding: 40vh 0;
background: lightgray;
}
.box {
width: 23%;
min-width: 100px;
height: 40vh;
margin-bottom: 10px;
background: lightblue;
display: inline-block;
}
.viewme {
transition: all .3s ease;
}
.viewme[data-view='inview-top'],
.viewme[data-view='inview-bottom'] {
opacity: 1;
transform: translateY(0);
}
.viewme[data-view='outview-top'] {
opacity: 0;
transform: translateY(-20px);
}
.viewme[data-view='outview-bottom'] {
opacity: 0;
transform: translateY(20px);
}
<p class="hi">Scroll down and back up</p>
<div class="box viewme"></div>
<div class="box viewme"></div>
<div class="box viewme"></div>
<div class="box viewme"></div>
<div class="box viewme"></div>
<div class="box viewme"></div>
<div class="box viewme"></div>
<div class="box viewme"></div>
<div class="box viewme"></div>
<div class="box viewme"></div>
<div class="box viewme"></div>
<div class="box viewme"></div>
<div class="box viewme"></div>
<div class="box viewme"></div>
<div class="box viewme"></div>
<div class="box viewme"></div>
<div class="box viewme"></div>
<div class="box viewme"></div>
<div class="box viewme"></div>
<div class="box viewme"></div>
<div class="box viewme"></div>
<div class="box viewme"></div>
<div class="box viewme"></div>
<div class="box viewme"></div>
<div class="box viewme"></div>
<div class="box viewme"></div>
<div class="box viewme"></div>
<div class="box viewme"></div>
<div class="box viewme"></div>
<div class="box viewme"></div>
<div class="box viewme"></div>
<div class="box viewme"></div>
<div class="box viewme"></div>
<div class="box viewme"></div>
<div class="box viewme"></div>
<div class="box viewme"></div>
<div class="box viewme"></div>
<div class="box viewme"></div>
<div class="box viewme"></div>
<div class="box viewme"></div>
<div class="box viewme"></div>
<div class="box viewme"></div>
<div class="box viewme"></div>
<div class="box viewme"></div>
<div class="box viewme"></div>
<div class="box viewme"></div>
<div class="box viewme"></div>
<div class="box viewme"></div>
<div class='margins'>
</div>
So far, I have two hints as to what might cause these problems:
Type error
between line 10 and 38 in my JS coderoot: document
do not work on iOS. Instead, they work when defining root: null
. However, I can not use root: null
because of rootBounds
. I've tried to wrap my html in a div and set the id of the div as the root element but that didn't work (see here).Any help to solve both problems is much appreciated. However, please do consider that I did not write the code above and don't understand it very well.
The IntersectionObserver API offers a better solution to this problem, and is now available in Safari Technology Preview, macOS 10.14.4 beta, and iOS 12.2 beta. Each IntersectionObserver has a set of target elements and observes the intersection of these targets with a particular root element or with the viewport.
If your Safari app is grayed and cannot be opened, it is possible that your old version iOS will not work on an up-to-date Safari. For solving it, you just need to update your iPhone.
When Safari on your iPhone stops working to load pages or stops responding, do not neglect the iOS system problem, especially after upgrading the latest iOS 15. Use the iOS diagnose tool to scan and fix your iOS system error and downgrade or upgrade iOS freely. “My Safari server stopped responding on iPhone 6, Why did it happen?”
1 Way 1. Check the Internet 2 Way 2. Check the URL 3 Way 3. Restart iPhone 4 Way 4. Clear History and Website Data 5 Way 5. Fix Safari Cannot Connect to Server without Data Loss 6 Way 6. Update Your Device 7 Way 7. Reset Network Settings 8 Way 8. Reset DNS Settings 9 Way 9. Fix Safari Cannot Connect to Server via iTunes Restore More ...
Although I can't put my finger on the exact cause of the bug, I do have a solution:
Try using document.body
as the root
and define sizes and scroll behavior to both html
and body
.
I think this relates to document
being more than a simple html node (I also tried using document.documentElement
without success) and how Safari initializes the box model for it.
Anyway, here's the updated working fiddle https://jsfiddle.net/gion_13/okrcgejt/8/ and screencasts of the tests on iOS and Mac Safari:
I couldn't find a solution to your problem but mine got solved when I reduced the threshold from 1 to 0.9. When it was set to 1, intersection observer wasn't working in Safari. But it worked perfectly in Firefox and Chrome.
const options={
root:null,
rootMargin:'0px',
threshold:0.9
};
It works whether the root is set to null or to document.body. For some reason, Intersection Observer in Safari wasn't working when I request it to only trigger when the object is 100% fully visible,but it works for 90%. I hope this helps someone out there.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With