Monday, May 20, 2024
 Popular · Latest · Hot · Upcoming
191
rated 0 times [  192] [ 1]  / answers: 1 / hits: 15921  / 4 Years ago, fri, may 29, 2020, 12:00:00

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:




  1. It does not work in Safari (latest version)

  2. It does not work on mobile Apple devices



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:




  1. In the Safari developer console, it says there is a Type error between line 10 and 38 in my JS code

  2. I have noticed that other scripts defining root: 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.


More From » jquery

 Answers
5

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:



enter
enter


[#50907] Wednesday, May 20, 2020, 4 Years  [reply] [flag answer]
Only authorized users can answer the question. Please sign in first, or register a free account.
alysas

Total Points: 616
Total Questions: 111
Total Answers: 124

Location: Slovenia
Member since Wed, Apr 6, 2022
2 Years ago
;