position:sticky stylefill

by Scott Kaye

JavaScript

"use strict";

const $sticky = Symbol("sticky");

// NodeList.forEach polyfill
if (!NodeList.forEach) {
    NodeList.prototype.forEach = Array.prototype.forEach;
}

// Polyfill if position:sticky isn't available
let el = document.createElement("div");
el.style.cssText = "position:sticky;";

if (el.style.position !== "sticky") {
    console.log("Polyfilling position:sticky");

    // Download and parse a stylesheet
    function getStylesheet(href) {
        return new Promise(resolve => {
            let xhr = new XMLHttpRequest();
            xhr.open("GET", href);
            xhr.onreadystatechange = () => {
                if (xhr.readyState !== 4) return;
                resolve(parseStylesheet(xhr.responseText));
            };
            xhr.send();
        });
    }

    function parseStylesheet(sheet) {
        let rules = [];
        const normalize = s => s.replace(/[\r\n\t\s]/g, "");

        let match;
        let matcher = /(.+?)\{([\s\S]+?)\}/g;
        while (match = matcher.exec(sheet)) {
            let selector = normalize(match[1]);
            let css = normalize(match[0]);
            let style = {};

            let subMatch;
            let subMatcher = /([a-z]+)\:(.+?);/g;
            while (subMatch = subMatcher.exec(css)) {
                style[subMatch[1]] = subMatch[2];
            }

            rules.push({
                selectorText: selector,
                cssText: css,
                style: style
            });
        }

        return rules;
    }

    // Unique key to store sticky values under
    let stickies = [];
    let stickySelectors = [];

    // Performs the actual "stick"
    function stick(node) {
        if (node[$sticky]) return;

        const parsePixels = s => s == "auto" ? null : parseInt(s);

        // Save values for how to stick this element
        let rect = node.getBoundingClientRect();

        // Yes, really
        node.style.display = "none";
        let actualComputedStyle =...