/* ===================================================================
UNSTICK ON TRIGGER — releases stick-to-top canvases
=================================================================== */
(function () {
var UNSTICK_CONFIG = {
/* ----------------------------- CUSTOMIZE -------------------------- */
triggerSelector: '.sticky-trigger',
stickySelectors: [
'.sticky-0',
'.sticky-1',
'.sticky-2',
'.sticky-3',
'.sticky-4',
'.sticky-5',
'.sticky-6',
'.sticky-7'
],
// Release line, measured from the top of the viewport.
// releaseUnit: 'px' → fixed pixels (same on every screen)
// releaseUnit: '%' → percent of viewport height (scales with screen)
releasePoint: 99, // specific number (no quotes, no unit)
releaseUnit: '%' // set to either 'px' or '%'
};
/* --------------------------- LEAVE AS IS --------------------------- */
var trigger = null;
var stickyEls = [];
var unstickY = 0;
var ticking = false;
function collectElements() {
trigger = document.querySelector(UNSTICK_CONFIG.triggerSelector);
stickyEls = [];
UNSTICK_CONFIG.stickySelectors.forEach(function (sel) {
document.querySelectorAll(sel).forEach(function (el) {
stickyEls.push(el);
});
});
}
function resolveReleasePoint() {
var n = parseFloat(UNSTICK_CONFIG.releasePoint) || 0;
if (UNSTICK_CONFIG.releaseUnit === '%') {
return window.innerHeight * (n / 100);
}
return n;
}
function measure() {
if (!trigger) return;
var rect = trigger.getBoundingClientRect();
var triggerDocTop = rect.top + window.scrollY;
unstickY = triggerDocTop - resolveReleasePoint();
update();
}
function update() {
if (!trigger || !stickyEls.length) return;
var delta = window.scrollY - unstickY;
stickyEls.forEach(function (el) {
if (delta > 0) {
el.style.setProperty('transform', 'translateY(' + (-delta) + 'px)', 'important');
} else {
el.style.removeProperty('transform');
}
});
}
function onScroll() {
if (ticking) return;
ticking = true;
requestAnimationFrame(function () {
update();
ticking = false;
});
}
function init() {
collectElements();
if (!trigger) return;
measure();
window.addEventListener('scroll', onScroll, { passive: true });
window.addEventListener('resize', measure);
window.addEventListener('load', measure);
if ('ResizeObserver' in window) {
new ResizeObserver(measure).observe(document.body);
}
}
if (document.readyState === 'loading') {
document.addEventListener('DOMContentLoaded', init);
} else {
init();
}
})();