-
Notifications
You must be signed in to change notification settings - Fork 212
Description
Hi @knadh,
Impacted component:
ot-dropdown
Description
The current implementation of the menu popover positioning in ot-dropdown causes layout thrashing (forced synchronous reflow). This occurs because the code interleaves DOM "read" operation (getBoundingClientRect) with DOM "write" operations (setting style.top) within the same execution frame.
Impact
- Jank: Visible stuttering when opening large dropdowns or scrolling while a popover is active.
- Main Thread Blocking: On low-end devices or complex pages, the browser is forced to recalculate the layout multiple times per frame, leading to dropped frames.
Technical Analysis
Bottleneck is located in this Anti-pattern position logic.
Lines 32 to 42 in 094ec48
| this.#position = () => { | |
| // Position has to be calculated and applied manually because | |
| // popover positioning is like fixed, relative to the window. | |
| const r = this.#trigger.getBoundingClientRect(); | |
| const m = this.#menu.getBoundingClientRect(); | |
| // Flip if menu overflows viewport. | |
| this.#menu.style.top = `${r.bottom + m.height > window.innerHeight ? r.top - m.height : r.bottom}px`; | |
| this.#menu.style.left = `${r.left + m.width > window.innerWidth ? r.right - m.width : r.left}px`; | |
| }; | |
| } |
Proposed Solution
- We should wrap the positioning logic in requestAnimationFrame and migrate from absolute positioning (top/left) to CSS transform (translate). This moves the workload to the compositor thread, leveraging GPU acceleration to avoid triggering expensive layout and paint cycles.
- Leverage the CSS Anchor Positioning API (position-anchor, position-area, and position-try-fallbacks) to handle popover placement. By moving positioning logic from the main thread to the browser's internal engine, we eliminate forced reflows and significantly reduce our JavaScript footprint
Browser Compatibility for CSS API
position-anchor
position-area
position-try-fallbacks
I prefer going with CSS APIs focusing on the goal to use minimal JS.
Does that align with the intended direction?
I have made the changes and tried out in my local. I will raise a PR for review.