JSFiddle - React, Tailwind, and code Playground

by tuanderful

HTML

<h3>Example of IntersectionObserver polyfill bug</h3>
<p>Occurs when using the intersectionObserver polyfill, and body has height of 100% and overflow-y: scroll.</p>
<p>Expected behavior: the callback should be called when the item scrolls in and out of view (when the threshold crosses 0).</p>
<p>Actual behavior: callback is called for #item1 when the threshold crosses 1. callback never called for #item2</p>
<em>Please see <a href="https://jsfiddle.net/tuanderful/a4zsv08p/6/" target="_blank">https://jsfiddle.net/tuanderful/a4zsv08p/6/</a> for an example of default behavior in Chrome.</em>

<div id="grid">
  <div id="item1" class="gridItem" style="top: 0; left: 0">
    When using the IntersectionObserver polyfill, slightly scrolling down causes the callback to be called (when the threshold crosses 1).
    <br />Expected behavior: the callback should be called when the item scrolls out of view (when the threshold crosses 0).
  </div>
  <div id="item2" class="gridItem" style="top: 2000px; left: 0">
    Expected behavior: the callback should be called when the item scrolls into view (threshold crosses 0).
    <br />Actual behavior: the callback is never called.
  </div>
</div>

CSS

body {
  // Disabling overflow-y "fixes" the issues
  height: 100%;
  overflow-y: scroll;
}

#grid {
  position: relative;
}

.gridItem {
  width: 200px;
  height: 300px;
  background: rgba(0, 0, 204, .6);
  position: absolute;
}

JavaScript

// Force the polyfill
delete window.IntersectionObserver;

/**
 * Copyright 2016 Google Inc. All Rights Reserved.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

(function(window, document) {
'use strict';


// Exits early if all IntersectionObserver and IntersectionObserverEntry
// features are natively supported.
if ('IntersectionObserver' in window &&
    'IntersectionObserverEntry' in window &&
    'intersectionRatio' in window.IntersectionObserverEntry.prototype) {
  return;
}


// Use :root element of the document for .contains() calls because older IEs
// support Node.prototype.contains only on Element nodes.
var docElement = document.documentElement;


/**
 * An IntersectionObserver registry. This registry exists to hold a strong
 * reference to IntersectionObserver instances currently observering a target
 * element. Without this registry, instances without another reference may be
 * garbage collected.
 */
var registry = [];


/**
 * Creates the global IntersectionObserverEntry constructor.
 * https://wicg.github.io/IntersectionObserver/#intersection-observer-entry
 * @param {Object} entry A dictionary of instance properties.
 * @constructor
 */
function IntersectionObserverEntry(entry) {
  this.time = entry.time;
  this.rootBounds = entry.rootBounds;
  this.boundingClientRect = entry.boundingClientRect;
  this.intersectionRect = entry.intersectionRect;
  this.target = entry.target;

  // Calculates the intersection ratio. Sets it to 0 if the...