Engineering Journal
Pdf Processor
Pdf Processor

Semantic and Spatial Layouts Can't Share a Ruler: Page Snap with IntersectionObserver

2026-05-30

TLDR

Synchronizing scroll positions between fixed physical PDF canvas pages (fixed $\sim 1100\text{px}$ height) and extracted reflowable HTML pages ($200\text{px}$ to $2500\text{px}$ dynamic height) via proportional ratio math (top / height) fails because spatial and semantic views lack vertical scale proportion. Replacing within-page ratio calculations with an IntersectionObserver page-snap coordinator anchored on matching data-page attributes provides precise synchronization across zoom levels.
Synchronization StrategyMetric UsedCSS Zoom ResiliencySynchronization Result
Proportional Height RatioPixel offsetTop & scrollTopDefective (Chromium zoom mismatch)Drifts & misaligns pages
IntersectionObserver Page-SnapViewport intersection ratio100% Zoom ResilientPrecise Page Alignment

Technical scroll synchronization engine

// IntersectionObserver Pane Observer for Page-Snap Synchronization
export function createPaneScrollObserver(containerPane, pageSelector, onActivePageChange) {
  const intersectionRatios = new Map();
  let currentActivePage = null;

const observer = new IntersectionObserver(entries => { for (const entry of entries) { intersectionRatios.set(entry.target, entry.intersectionRatio); }

let mostVisibleElement = null; let highestRatio = -1;

for (const [element, ratio] of intersectionRatios) { if (ratio > highestRatio) { highestRatio = ratio; mostVisibleElement = element; } }

if (!mostVisibleElement) return;

const pageId = mostVisibleElement.getAttribute('data-page'); if (pageId !== currentActivePage) { currentActivePage = pageId; onActivePageChange(pageId); } }, { root: containerPane, threshold: [0, 0.25, 0.5, 0.75, 1.0] });

const pageElements = containerPane.querySelectorAll(pageSelector); pageElements.forEach(pageEl => observer.observe(pageEl));

return observer; }

Rule of thumb: Synchronize multi-pane document editors using browser-native IntersectionObserver page anchors rather than proportional pixel scroll offsets.
Read this post in the full Engineering Journal →