When performance or visual stability matters (e.g., zoom/antialiasing), prefer precision-first measurement and avoid expensive DOM churn.
Apply these rules: 1) Use high-precision resize measurements
clientWidth/clientHeight when jitter appears during zoom.ResizeObserver and read borderBoxSize (more stable than layout-derived rounded values).visualViewport resize when zoom changes affect rendering.2) Inject shared resources only once (or reference-count)
<style>, <canvas>, or other shared DOM/CSS, create/inject it a single time.<style> nodes on mount/unmount; it’s often more expensive than keeping them.Example pattern:
class ExampleMount {
private parentWidth = 0;
private parentHeight = 0;
private resizeObserver: ResizeObserver | null = null;
constructor(private parentElement: HTMLElement) {
// Singleton style injection
if (!document.querySelector('style[data-my-component]')) {
const style = document.createElement('style');
style.setAttribute('data-my-component', '');
style.textContent = '/* shared styles */';
document.head.prepend(style);
}
this.resizeObserver = new ResizeObserver(([entry]) => {
const size = entry?.borderBoxSize?.[0];
if (size) {
this.parentWidth = size.inlineSize;
this.parentHeight = size.blockSize;
}
// recompute render scale / canvas size using parentWidth/parentHeight
});
this.resizeObserver.observe(this.parentElement);
// Optional: visual viewport changes can affect zoom-related rendering
visualViewport?.addEventListener('resize', () => {
// recompute render scale / canvas size
// (avoid clientWidth/clientHeight if jitter is observed)
});
}
}
This standard reduces resize jitter and prevents unnecessary DOM operations—both common sources of UI performance regressions.