You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
On REAL mobile devices (iOS Safari and Android Chrome), the example-blog top navbar flickers on a FORWARD client-router navigation (scroll down the home post list, tap a post like "Hello World!"), but NOT when using the browser Back button. Desktop does not show it, and crucially Chrome DevTools mobile emulation does not show it either, so it can only be observed on a physical phone.
The navbar is the root layout's <header>, which sits OUTSIDE the <!--wj:children--> slot, so the client router preserves its DOM identity across a soft nav (it is never recreated). This is therefore NOT a layout-recreation bug. It is a paint artifact.
Design / approach
Mechanism (grounded in the code):
The header is position: sticky plus backdrop-blur-[18px] backdrop-saturate-[180%] (examples/blog/app/layout.ts ~L207). A backdrop-filter continuously re-samples and re-blurs the content behind it.
The blog has no loading.* boundary, so forward nav is a single content swap (no optimistic skeleton). The real forward-vs-back difference is the scroll: forward jumps to top via window.scrollTo({ top: 0, left: 0, behavior: 'instant' }) (added in fix: force instant scroll on navigation so smooth CSS does not animate it #603); back restores the previous scroll position.
After fix: force instant scroll on navigation so smooth CSS does not animate it #603 the forward scroll-to-top is INSTANT (it was animated scroll-behavior: smooth before). On a large single-frame jump the sticky header's backdrop-filter must re-rasterize its entire blurred backdrop in one frame. Weaker mobile GPUs show a one-frame stale-blur flicker; the desktop compositor (and DevTools device mode, which runs Blink and does not emulate the mobile GPU) composites it fast enough to hide it. iOS Safari is WebKit, with its own known backdrop-filter + sticky quirks that Chrome DevTools cannot reproduce at all.
The instant scroll itself is correct (it fixed #601 and matches a native page load), so the fix is NOT to revert it. The fix belongs in the blog CSS: promote the header to its own compositor layer so the blur composites cleanly through an instant scroll, e.g. add transform: translateZ(0) / will-change: transform (and the -webkit- equivalents for Safari) to the <header>, and/or trim the backdrop-filter. Try the compositor hint first (cheapest, most likely fix); fall back to reducing/removing the blur if it persists.
Implementation notes (for the implementing agent)
Where to edit: examples/blog/app/layout.ts, the <header class="sticky top-0 z-20 ... backdrop-blur-[18px] backdrop-saturate-[180%]"> element (~L207). This is light-DOM Tailwind in a page/layout; a one-off compositor hint can go via a utility class or a small tag-prefixed CSS rule in the layout's <style> block (invariant 7: a light-DOM custom CSS class selector must be tag-prefixed, but the header is a plain element in a layout, so a scoped rule is fine).
Landmines: this CANNOT be reproduced on desktop or in Chrome DevTools device mode. Verify ONLY on a real phone in BOTH iOS Safari and Android Chrome. Do not declare it fixed off desktop testing. will-change: transform left on permanently can raise memory on some devices; prefer transform: translateZ(0) (a static compositor promotion) over a permanent will-change if either works.
Tests + docs: this is a visual/rendering fix with no automated-test surface (the flicker is GPU/compositor-dependent and invisible to headless/emulated browsers). Note in the PR that verification is manual-on-device. No docs-site / AGENTS.md change (blog-app CSS only).
Acceptance criteria
On a real iOS Safari device, forward nav (scroll the post list, tap a post) shows no navbar flicker
On a real Android Chrome device, same: no navbar flicker
Back navigation still has no flicker (no regression)
The header still renders its intended blur/translucency (the fix does not visually degrade it on desktop)
No automated test added (documented why: GPU/compositor artifact, not reproducible headless); manual on-device verification recorded in the PR
Problem
On REAL mobile devices (iOS Safari and Android Chrome), the example-blog top navbar flickers on a FORWARD client-router navigation (scroll down the home post list, tap a post like "Hello World!"), but NOT when using the browser Back button. Desktop does not show it, and crucially Chrome DevTools mobile emulation does not show it either, so it can only be observed on a physical phone.
The navbar is the root layout's
<header>, which sits OUTSIDE the<!--wj:children-->slot, so the client router preserves its DOM identity across a soft nav (it is never recreated). This is therefore NOT a layout-recreation bug. It is a paint artifact.Design / approach
Mechanism (grounded in the code):
position: stickyplusbackdrop-blur-[18px] backdrop-saturate-[180%](examples/blog/app/layout.ts~L207). Abackdrop-filtercontinuously re-samples and re-blurs the content behind it.loading.*boundary, so forward nav is a single content swap (no optimistic skeleton). The real forward-vs-back difference is the scroll: forward jumps to top viawindow.scrollTo({ top: 0, left: 0, behavior: 'instant' })(added in fix: force instant scroll on navigation so smooth CSS does not animate it #603); back restores the previous scroll position.scroll-behavior: smoothbefore). On a large single-frame jump the sticky header'sbackdrop-filtermust re-rasterize its entire blurred backdrop in one frame. Weaker mobile GPUs show a one-frame stale-blur flicker; the desktop compositor (and DevTools device mode, which runs Blink and does not emulate the mobile GPU) composites it fast enough to hide it. iOS Safari is WebKit, with its own knownbackdrop-filter+ sticky quirks that Chrome DevTools cannot reproduce at all.The instant scroll itself is correct (it fixed #601 and matches a native page load), so the fix is NOT to revert it. The fix belongs in the blog CSS: promote the header to its own compositor layer so the blur composites cleanly through an instant scroll, e.g. add
transform: translateZ(0)/will-change: transform(and the-webkit-equivalents for Safari) to the<header>, and/or trim the backdrop-filter. Try the compositor hint first (cheapest, most likely fix); fall back to reducing/removing the blur if it persists.Implementation notes (for the implementing agent)
examples/blog/app/layout.ts, the<header class="sticky top-0 z-20 ... backdrop-blur-[18px] backdrop-saturate-[180%]">element (~L207). This is light-DOM Tailwind in a page/layout; a one-off compositor hint can go via a utility class or a small tag-prefixed CSS rule in the layout's<style>block (invariant 7: a light-DOM custom CSS class selector must be tag-prefixed, but the header is a plain element in a layout, so a scoped rule is fine).will-change: transformleft on permanently can raise memory on some devices; prefertransform: translateZ(0)(a static compositor promotion) over a permanentwill-changeif either works.packages/core/src/router-client.js(fix: force instant scroll on navigation so smooth CSS does not animate it #603) is correct and must NOT be reverted; the flicker is the blog header's rendering, not the router.htmltemplate bodies (feat(server): replace esbuild TS stripping with Node 24+ strip-types #9); no banned prose punctuation in comments (release: bump core/server/cli versions, honest engines fields #11).Acceptance criteria