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 =...