title: IntersectionObserver not working in Safari or iOS
body: <p>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.</p>
  
  <p>It uses the <a href="https://developer.mozilla.org/en-US/docs/Web/API/Intersection_Observer_API" rel="noreferrer">Intersection Observer</a> because it is supposed to handle large amounts of elements better than <code>scroll</code> events. </p>
  
  <p>However, I am facing two problems with this code: </p>
  
  <ol>
  <li>It does not work in Safari (latest version)</li>
  <li>It does not work on mobile Apple devices</li>
  </ol>
  
  <p>This is odd because the IntersectionObserver should work fine on Safari and even mobile browsers on iOS. </p>
  
  <p>You can <a href="https://jsfiddle.net/sublines/6sfuj2yo/94/" rel="noreferrer">find the code on jsFiddle</a> or see the snippet here:</p>
  
  <p><div class="snippet" data-lang="js" data-hide="false" data-console="true" data-babel="false">
  <div class="snippet-code">
  <pre class="snippet-code-js lang-js prettyprint-override"><code>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 =&gt; x / 29)
  };
  
  let observer = new IntersectionObserver(function(entries, observer) {
  
    entries.forEach((entry, index) =&gt; {
      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 &lt; rootTop &amp;&amp; bottomBound &lt; rootTop) {
        className = "outview-top";
      } else if (topBound &gt; rootBottom) {
        className = "outview-bottom";
      } else if (topBound &lt; rootBottom &amp;&amp; bottomBound &gt; rootBottom) {
        className = "inview-bottom";
      } else if (topBound &lt; rootTop &amp;&amp; bottomBound &gt; rootTop) {
        className = "inview-top";
      }
      element.setAttribute('data-view', className);
  
    });
  }, config);
  
  const viewbox = document.querySelectorAll('.viewme');
  viewbox.forEach(image =&gt; {
    observer.observe(image);
  });</code></pre>
  <pre class="snippet-code-css lang-css prettyprint-override"><code>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);
  }</code></pre>
  <pre class="snippet-code-html lang-html prettyprint-override"><code>&lt;p class="hi"&gt;Scroll down and back up&lt;/p&gt;
  &lt;div class="box viewme"&gt;&lt;/div&gt;
  &lt;div class="box viewme"&gt;&lt;/div&gt;
  &lt;div class="box viewme"&gt;&lt;/div&gt;
  &lt;div class="box viewme"&gt;&lt;/div&gt;
  &lt;div class="box viewme"&gt;&lt;/div&gt;
  &lt;div class="box viewme"&gt;&lt;/div&gt;
  &lt;div class="box viewme"&gt;&lt;/div&gt;
  &lt;div class="box viewme"&gt;&lt;/div&gt;
  &lt;div class="box viewme"&gt;&lt;/div&gt;
  &lt;div class="box viewme"&gt;&lt;/div&gt;
  &lt;div class="box viewme"&gt;&lt;/div&gt;
  &lt;div class="box viewme"&gt;&lt;/div&gt;
  &lt;div class="box viewme"&gt;&lt;/div&gt;
  &lt;div class="box viewme"&gt;&lt;/div&gt;
  &lt;div class="box viewme"&gt;&lt;/div&gt;
  &lt;div class="box viewme"&gt;&lt;/div&gt;
  &lt;div class="box viewme"&gt;&lt;/div&gt;
  &lt;div class="box viewme"&gt;&lt;/div&gt;
  &lt;div class="box viewme"&gt;&lt;/div&gt;
  &lt;div class="box viewme"&gt;&lt;/div&gt;
  &lt;div class="box viewme"&gt;&lt;/div&gt;
  &lt;div class="box viewme"&gt;&lt;/div&gt;
  &lt;div class="box viewme"&gt;&lt;/div&gt;
  &lt;div class="box viewme"&gt;&lt;/div&gt;
  &lt;div class="box viewme"&gt;&lt;/div&gt;
  &lt;div class="box viewme"&gt;&lt;/div&gt;
  &lt;div class="box viewme"&gt;&lt;/div&gt;
  &lt;div class="box viewme"&gt;&lt;/div&gt;
  &lt;div class="box viewme"&gt;&lt;/div&gt;
  &lt;div class="box viewme"&gt;&lt;/div&gt;
  &lt;div class="box viewme"&gt;&lt;/div&gt;
  &lt;div class="box viewme"&gt;&lt;/div&gt;
  &lt;div class="box viewme"&gt;&lt;/div&gt;
  &lt;div class="box viewme"&gt;&lt;/div&gt;
  &lt;div class="box viewme"&gt;&lt;/div&gt;
  &lt;div class="box viewme"&gt;&lt;/div&gt;
  &lt;div class="box viewme"&gt;&lt;/div&gt;
  &lt;div class="box viewme"&gt;&lt;/div&gt;
  &lt;div class="box viewme"&gt;&lt;/div&gt;
  &lt;div class="box viewme"&gt;&lt;/div&gt;
  &lt;div class="box viewme"&gt;&lt;/div&gt;
  &lt;div class="box viewme"&gt;&lt;/div&gt;
  &lt;div class="box viewme"&gt;&lt;/div&gt;
  &lt;div class="box viewme"&gt;&lt;/div&gt;
  &lt;div class="box viewme"&gt;&lt;/div&gt;
  &lt;div class="box viewme"&gt;&lt;/div&gt;
  &lt;div class="box viewme"&gt;&lt;/div&gt;
  &lt;div class="box viewme"&gt;&lt;/div&gt;
  
  &lt;div class='margins'&gt;
  
  &lt;/div&gt;</code></pre>
  </div>
  </div>
  </p>
  
  <p>So far, I have two hints as to what might cause these problems: </p>
  
  <ol>
  <li>In the Safari developer console, it says there is a <code>Type error</code> between line 10 and 38 in my JS code</li>
  <li>I have noticed that other scripts defining <code>root: document</code> do not work on iOS. Instead, they work when defining <code>root: null</code>. However, I can not use <code>root: null</code> because of <code>rootBounds</code>. 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 (<a href="https://jsfiddle.net/sublines/6sfuj2yo/98/" rel="noreferrer">see here</a>).</li>
  </ol>
  
  <p>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.</p>