Skip to content

fix(navbar): keep the navbar and body in sync when switching color mode#2000

Merged
markdumay merged 3 commits into
mainfrom
fix/color-mode-sync
Jul 11, 2026
Merged

fix(navbar): keep the navbar and body in sync when switching color mode#2000
markdumay merged 3 commits into
mainfrom
fix/color-mode-sync

Conversation

@markdumay

Copy link
Copy Markdown
Collaborator

Switching between light and dark mode changed the navbar and the body at visibly different times.

Problem

The navbar does not inherit the document's color mode. navbar.js gives it its own data-bs-theme attribute so it can adapt to the section beneath it, and on a color mode switch that attribute was only reassigned after a hardcoded 600ms delay — longer than the body's 0.5s transition. The body finished fading before the navbar began.

Measured on the exampleSite, scrolled down, dark → light (background red channel):

time body navbar
0–537ms 255 → 33 (fading) 255 (unchanged)
604ms 33 (settled) attribute finally flips
604–1137ms 33 255 → 33 (fading)

Two smaller defects compounded it:

  • The body and navbar each declared their own transition. The body omitted a timing function and so defaulted to ease, while the navbar asked for ease-in-out. Same 0.5s, but they diverged by up to 77/255 mid-flight.
  • A transparent navbar was worse: .navbar[data-transparent="true"] shares the specificity of the color mode rule but comes later, so it replaced the transition entirely and animated over 0.3s.

Changes

Three commits, one per concern:

  1. fix(theme) — define the transition once as $theme-mode-transition and use it for every element that repaints on a switch. The transparent navbar keeps its faster curve for the backdrop blur, which is a scroll effect, not a color mode one.
  2. fix(navbar) — assign targetTheme rather than defaultTheme, which was null at the top of a page without an overlay and stored the string "null".
  3. fix(navbar) — drop the 600ms delay. It existed because the navbar samples the background beneath it and would otherwise read a color the body is still fading through. Reading --bs-body-bg instead solves that at the source: custom properties are not animated, so the property holds the target color from the outset. Sampling no longer depends on the transition, so the navbar updates immediately and the delay (and its sleep helper) can go.

Verification

Sampled both elements every animation frame through real toggles. Maximum divergence in the background red channel, previously up to 77/255 with the navbar a further ~600ms behind:

case result
scrolled, both directions gap 0 — in sync
at top, both directions gap 0 — in sync
transparent navbar, scrolled gap 0 — in sync

The behaviour the changed rules protect still works: the navbar's theme attribute is a valid mode at every scroll position, data-bs-overlay still wins at the top of an overlay page, and the transparent navbar is still clear at the top with blur(10px) once scrolled. The transparent cases were exercised by temporarily enabling navigation.transparent, which is off in the exampleSite.

🤖 Generated with Claude Code

markdumay and others added 3 commits July 11, 2026 11:58
The body and the navbar each declared their own transition for a color mode switch. The
body omitted a timing function, so it defaulted to ease, while the navbar asked for
ease-in-out. Both ran for 0.5s and therefore started and ended together, but they drifted
by up to 77/255 in between, with the body running ahead.

A transparent navbar was worse off: its own rule shares the specificity of the color mode
rule but comes later, so it replaced the transition altogether and animated over 0.3s.

Define the transition once as $theme-mode-transition and use it for every element that
repaints on a switch. The transparent navbar keeps the faster curve for its backdrop
filter, which is a scroll effect rather than a color mode one.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
At the top of a page without an overlay, the navbar assigned defaultTheme, which is null
there, so setAttribute stored the string "null". The guard above it already computed
targetTheme, which falls back to the stored color mode. Assign that instead.

The invalid value happened to be harmless, as the navbar then inherited the color mode from
the document, but it left the navbar claiming a theme that does not exist.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The navbar carries its own data-bs-theme, so it only repaints once that attribute is
reassigned. On a color mode switch that reassignment was deferred by 600ms, which is longer
than the 0.5s transition of the body. The body therefore completed its fade before the
navbar started its own, leaving the two visibly out of step.

The delay was there because the navbar samples the background beneath it and would
otherwise read a color the body is still fading through. Read that color from the
--bs-body-bg custom property instead: custom properties are not animated, so it holds the
target color from the outset. Sampling is now independent of the transition, so the navbar
can update immediately and the delay can go, along with the sleep helper that served it.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@netlify

netlify Bot commented Jul 11, 2026

Copy link
Copy Markdown

Deploy Preview for gethinode-demo ready!

Name Link
🔨 Latest commit 4c5fab6
🔍 Latest deploy log https://app.netlify.com/projects/gethinode-demo/deploys/6a521439b2958300084a6c76
😎 Deploy Preview https://deploy-preview-2000--gethinode-demo.netlify.app
📱 Preview on mobile
Toggle QR Code...

QR Code

Use your smartphone camera to open QR code link.

To edit notification comments on pull requests, go to your Netlify project configuration.

@markdumay markdumay enabled auto-merge July 11, 2026 10:06
@markdumay markdumay merged commit 5fa88b9 into main Jul 11, 2026
16 checks passed
@markdumay markdumay deleted the fix/color-mode-sync branch July 11, 2026 10:06
@markdumay

Copy link
Copy Markdown
Collaborator Author

🎉 This PR is included in version 2.19.3 🎉

The release is available on GitHub release

Your semantic-release bot 📦🚀

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant