docs: keep banner height in sync via ResizeObserver#9330
Conversation
The height CSS variable was set once in a single rAF and never updated afterward. On window resize, orientation change, or text reflow the banner height could change, leaving the VitePress nav offset stale and causing overlap or a visible gap. Observe the banner element and resync the variable whenever its size changes; disconnect the observer when the banner is dismissed. Co-Authored-By: Claude Opus 4.7 (1M context) <[email protected]>
Greptile SummaryThis PR replaces the one-shot Confidence Score: 5/5Safe to merge — small, focused fix with no logic issues. The change is minimal and correct. The ResizeObserver guard handles SSR and older browsers, cleanup on dismiss is properly handled, and the retained requestAnimationFrame gives an early initial sync for browsers where ResizeObserver may fire slightly later. No P0/P1 issues found. No files require special attention. Important Files Changed
Sequence DiagramsequenceDiagram
participant Fetch as fetch(banner.json)
participant Render as render()
participant DOM as document.body
participant RAF as requestAnimationFrame
participant RO as ResizeObserver
participant CSS as CSS variable
Fetch->>Render: banner data
Render->>DOM: prepend(el)
Render->>RAF: schedule syncHeight
Render->>RO: observe(el)
RAF->>CSS: set --vp-layout-top-height (initial)
RO->>CSS: set --vp-layout-top-height (on every resize)
note over RO,CSS: Fires on resize, orientation change, text reflow
DOM-->>RO: dismiss click
RO->>RO: disconnect()
DOM->>CSS: removeProperty(--vp-layout-top-height)
Reviews (1): Last reviewed commit: "docs: keep --vp-layout-top-height in syn..." | Re-trigger Greptile |
There was a problem hiding this comment.
Code Review
This pull request introduces a ResizeObserver to dynamically synchronize the banner's height with the --vp-layout-top-height CSS variable. A review comment identified a potential race condition where the height synchronization logic could execute after the banner is dismissed, potentially resetting the CSS variable to zero; a suggestion was made to add a connection check to prevent this behavior.
| const syncHeight = () => { | ||
| document.documentElement.style.setProperty( | ||
| "--vp-layout-top-height", | ||
| `${el.offsetHeight}px`, | ||
| ); | ||
| }; |
There was a problem hiding this comment.
There is a potential race condition here. If the banner is dismissed (via the button click) before the requestAnimationFrame or a ResizeObserver notification fires, syncHeight will execute on a detached element. This will result in el.offsetHeight being 0, which then re-adds the --vp-layout-top-height property to the document as 0px after it was explicitly removed in the click handler. Adding a check for el.isConnected ensures the property is only updated if the banner is still active in the DOM.
| const syncHeight = () => { | |
| document.documentElement.style.setProperty( | |
| "--vp-layout-top-height", | |
| `${el.offsetHeight}px`, | |
| ); | |
| }; | |
| const syncHeight = () => { | |
| if (!el.isConnected) return; | |
| document.documentElement.style.setProperty( | |
| "--vp-layout-top-height", | |
| `${el.offsetHeight}px`, | |
| ); | |
| }; |
Hyperfine Performance
|
| Command | Mean [ms] | Min [ms] | Max [ms] | Relative |
|---|---|---|---|---|
mise-2026.4.19 x -- echo |
25.0 ± 0.5 | 23.9 | 26.6 | 1.00 |
mise x -- echo |
25.8 ± 1.0 | 24.7 | 39.2 | 1.03 ± 0.05 |
mise env
| Command | Mean [ms] | Min [ms] | Max [ms] | Relative |
|---|---|---|---|---|
mise-2026.4.19 env |
24.6 ± 0.6 | 23.4 | 30.4 | 1.00 |
mise env |
25.5 ± 0.6 | 24.4 | 27.9 | 1.03 ± 0.04 |
mise hook-env
| Command | Mean [ms] | Min [ms] | Max [ms] | Relative |
|---|---|---|---|---|
mise-2026.4.19 hook-env |
25.6 ± 0.5 | 24.2 | 27.4 | 1.00 |
mise hook-env |
26.4 ± 0.4 | 25.2 | 28.2 | 1.03 ± 0.03 |
mise ls
| Command | Mean [ms] | Min [ms] | Max [ms] | Relative |
|---|---|---|---|---|
mise-2026.4.19 ls |
23.1 ± 1.1 | 21.9 | 39.3 | 1.00 |
mise ls |
23.3 ± 0.4 | 22.3 | 26.2 | 1.01 ± 0.05 |
xtasks/test/perf
| Command | mise-2026.4.19 | mise | Variance |
|---|---|---|---|
| install (cached) | 170ms | 175ms | -2% |
| ls (cached) | 81ms | 82ms | -1% |
| bin-paths (cached) | 86ms | 88ms | -2% |
| task-ls (cached) | 811ms | 802ms | +1% |
### 🐛 Bug Fixes - **(config)** resolve relative path: tool versions against config root by @jdx in [#9320](#9320) - **(lock)** resolve @latest and prune poisoned lockfile entries by @jdx in [#9321](#9321) - fix - be able to work with regex in attestation check by @monotek in [#9327](#9327) ### 🚜 Refactor - **(aqua)** bake aqua registry from merged yaml by @risu729 in [#9043](#9043) ### 📚 Documentation - add cross-site announcement banner by @jdx in [#9326](#9326) - keep banner height in sync via ResizeObserver by @jdx in [#9330](#9330) - respect banner expires field by @jdx in [#9334](#9334) ### 📦️ Dependency Updates - bump communique to 1.0.2 by @jdx in [#9313](#9313) - bump communique to 1.0.3 by @jdx in [#9332](#9332) - update actions/setup-node digest to 48b55a0 by @renovate[bot] in [#9339](#9339) - update ghcr.io/jdx/mise:alpine docker digest to a92efa5 by @renovate[bot] in [#9340](#9340) - update ghcr.io/jdx/mise:rpm docker digest to 5c24f69 by @renovate[bot] in [#9343](#9343) - update rust docker digest to e4f09e8 by @renovate[bot] in [#9345](#9345) - update rui314/setup-mold digest to 9c9c13b by @renovate[bot] in [#9344](#9344) - update ghcr.io/jdx/mise:deb docker digest to a3afe3e by @renovate[bot] in [#9342](#9342) - update ghcr.io/jdx/mise:copr docker digest to 4098d5a by @renovate[bot] in [#9341](#9341) - update taiki-e/install-action digest to 74e87cb by @renovate[bot] in [#9346](#9346) ### Chore - **(ci)** remove cargo-vendor install from ppa publish by @jdx in [#9312](#9312) - **(release)** publish snap to stable channel by @jdx in [#9318](#9318) - remove FUNDING.yml in favor of jdx/.github default by @jdx in [#9331](#9331) ## 📦 Aqua Registry Updated [aqua-registry](https://github.com/aquaproj/aqua-registry): [v4.492.0](https://github.com/aquaproj/aqua-registry/releases/tag/v4.492.0) -> [v4.498.0](https://github.com/aquaproj/aqua-registry/releases/tag/v4.498.0). Included aqua-registry releases: - [v4.493.0](https://github.com/aquaproj/aqua-registry/releases/tag/v4.493.0) - [v4.494.0](https://github.com/aquaproj/aqua-registry/releases/tag/v4.494.0) - [v4.494.1](https://github.com/aquaproj/aqua-registry/releases/tag/v4.494.1) - [v4.495.0](https://github.com/aquaproj/aqua-registry/releases/tag/v4.495.0) - [v4.496.0](https://github.com/aquaproj/aqua-registry/releases/tag/v4.496.0) - [v4.497.0](https://github.com/aquaproj/aqua-registry/releases/tag/v4.497.0) - [v4.498.0](https://github.com/aquaproj/aqua-registry/releases/tag/v4.498.0)
Summary
Follow-up fix for the banner.
`--vp-layout-top-height` was set once in a single rAF and never updated. On window resize, orientation change, or text reflow the banner height could change, leaving VitePress's nav offset stale and causing overlap or a visible gap. Observe the banner element and resync the variable whenever its size changes; disconnect the observer on dismiss.
\U0001F916 Generated with Claude Code
Note
Low Risk
Low risk: docs-only UI behavior change that updates a CSS variable on resize/reflow; main risk is minor layout/perf issues if observation behaves unexpectedly in some browsers.
Overview
Keeps the VitePress top layout offset (
--vp-layout-top-height) in sync with the docs announcement banner by extracting asyncHeight()helper and wiring it to aResizeObserver.On dismiss, the observer is disconnected before removing the banner and clearing the CSS variable; initial height is still set via
requestAnimationFrame, with a graceful no-ResizeObserverfallback.Reviewed by Cursor Bugbot for commit 974aafb. Bugbot is set up for automated code reviews on this repo. Configure here.