title: Why is IntersectionObserver triggered well before in viewport?
body: <p>IntersectionObserver seems to be triggering well before it should in my scenario (yes, I've read quite a few Q&amp;A's here and several guides published around the place).</p>
  <p>I'm applying a class <em>after</em> an observed element leaves the viewport. This works in general as you scroll down the page, but on page load, the next element, outside the viewport (could be <code>#box2</code> or <code>#box3</code> depending on your browser height) gets the viewed class, before it ever enters the viewport. <a href="https://codepen.io/erland/pen/WNzqYrq" rel="nofollow noreferrer">Here's a codepen</a>.</p>
  <p>Can anyone explain <strong>why the observed element <em>after the one/s that are in viewport</em> have the viewed class (<code>.js-was-active</code>) on page load, before they intersect the viewport</strong> – and the (presumably obvious) error I've made somewhere?!</p>
  <p>Bonus, possibly related, question (while trying to debug the issue above, I shifted the bottom margin of the observer up 50%, but it's triggering as soon as any observed elements enter the viewport, not halfway up, despite <code>rootMargin: '0% 0% -50% 0%'</code>. Why?</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 steps = document.querySelectorAll('.js-iobserve');
  const ioConfig = { rootMargin: '0% 0% -50% 0%' };
  var isLeaving = false;
  observer = new IntersectionObserver(entries =&gt; {
    entries.forEach(entry =&gt; {
      var match = '.' + entry.target.getAttribute('id');
      if (entry.isIntersecting) {
        isLeaving = true;
        entry.target.classList.add('js-is-active');
        $(match).addClass('js-is-active');
      } else if (isLeaving) {
        isLeaving = false;
        entry.target.classList.remove('js-is-active');
        entry.target.classList.add('js-was-active');
        $(match).removeClass('js-is-active').addClass('js-was-active');
      }
    });
  }, ioConfig);
  
  $(document).ready(function() {
    steps.forEach(step =&gt; {
      observer.observe(step);
    });
  });</code></pre>
  <pre class="snippet-code-css lang-css prettyprint-override"><code>.js-is-active {
    border: 4px dashed red;
  }
  .js-was-active {
    opacity: .5;
  }</code></pre>
  <pre class="snippet-code-html lang-html prettyprint-override"><code>&lt;script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"&gt;&lt;/script&gt;
  &lt;header class="container-fluid py-4"&gt;
    &lt;h1 class="text-center"&gt;HEADER&lt;/h1&gt;
  &lt;/header&gt;
  
  &lt;div class="container mt-5"&gt;
    &lt;div class="row"&gt;
      &lt;div class="col"&gt;
        &lt;div id="box1" class="d-flex justify-content-center align-items-center bg-info mb-5 js-iobserve" style="height:67vh;"&gt;BOX ONE&lt;/div&gt;
        &lt;div class="my-5 py-5"&gt;&lt;/div&gt;
        &lt;div id="box2" class="d-flex justify-content-center align-items-center bg-danger mb-5 js-iobserve" style="height:67vh;"&gt;BOX TWO&lt;/div&gt;
        &lt;div class="my-5 py-5"&gt;&lt;/div&gt;
        &lt;div id="box3" class="d-flex justify-content-center align-items-center bg-warning mb-5 js-iobserve" style="height:67vh;"&gt;BOX THREE&lt;/div&gt;
        &lt;div class="my-5 py-5"&gt;&lt;/div&gt;
        &lt;div id="box4" class="d-flex justify-content-center align-items-center bg-success mb-5 js-iobserve" style="height:67vh;"&gt;BOX FOUR&lt;/div&gt;
        &lt;div class="my-5 py-5"&gt;&lt;/div&gt;
        &lt;div id="box5" class="d-flex justify-content-center align-items-center bg-info mb-5 js-iobserve" style="height:67vh;"&gt;BOX FIVE&lt;/div&gt;
        &lt;div class="my-5 py-5"&gt;&lt;/div&gt;
      &lt;/div&gt;
      &lt;div class="col"&gt;
        &lt;div class="position-sticky" style="top:2rem;"&gt;
          &lt;h2 class="box1"&gt;Box one heading&lt;/h2&gt;
          &lt;h2 class="box2"&gt;Box two heading &lt;br/&gt;&lt;small&gt;Why does this have the active class on page load when my rootMargin is -50% on the bottom edge?&lt;/small&gt;&lt;/h2&gt;
          &lt;h2 class="box3"&gt;Box three heading &lt;br/&gt;&lt;small&gt;Why does the io think I've seen this already on page load?&lt;/small&gt;&lt;/h2&gt;
          &lt;h2 class="box4"&gt;Box four heading&lt;/h2&gt;
          &lt;h2 class="box5"&gt;Box five heading&lt;/h2&gt;
        &lt;/div&gt;
      &lt;/div&gt;
    &lt;/div&gt;
  &lt;/div&gt;</code></pre>
  </div>
  </div>
  </p>