Darkmode flickers on page load
NetBox Edition
NetBox Community
NetBox Version
v4.4.7
Python Version
3.12
Steps to Reproduce
- Open Netbox in Chrome
- Enable darkmode
- Swap between different pages / Refresh page
https://github.com/user-attachments/assets/dd295383-d506-45a3-81fd-20c4d1e2720f
Expected Behavior
Darkmode remains consistent when changing pages.
Observed Behavior
Darkmode flickers when changing pages, briefly showing default color mode.
Thanks for the report. This is a known limitation, when navigating between pages, the browser briefly renders before setmode.js executes and reapplies your dark mode preference from localStorage. It could maybe be eliminated by inlining the script in the template, but it's purely cosmetic and the core team isn't likely to prioritize it soon. We'd welcome a community contribution if someone wants to tackle it.
Related: #15340, #16003
Heck I'll take a look. Might be cosmetic but I'm hating this flashbang every time I swap pages ;)
@jnovinger is there any reason why the CSS styling applies to body instead of html/root for dark mode styling?
My best guess at the issue is the rework to how the dark mode works in the 4.x release to be client-side entirely. (This has been around for a year and no one complained? I might be wrong.)
This section updates the theme:
function updateElements(targetMode: ColorMode): void {
const body = document.querySelector('body');
if (body && targetMode == 'dark') {
body.setAttribute('data-bs-theme', 'dark');
} else if (body) {
body.setAttribute('data-bs-theme', 'light');
}
This script is being run after the page renders to update the body's data-bs-theme attribute, however if the body exists the user can already see it causing a flicker.
There is setmode.js in static which loads before the DOM, but this can't set the body attribute (AFAIK) since it's run before the body is created.
function setMode(mode) {
document.documentElement.setAttribute("data-bs-theme", mode);
localStorage.setItem("netbox-color-mode", mode);
}
A potential way to do this is to have the dark mode styling refer to the <html> element instead of <body>, and have the updateElements function update the <html> attribute.
E.g.:
function updateElements(targetMode: ColorMode): void {
if (targetMode == 'dark') {
document.documentElement.setAttribute("data-bs-theme", 'dark');
} else {
document.documentElement.setAttribute("data-bs-theme", 'light');
}
^^ Similar to setMode
html[data-bs-theme=light] .navbar-vertical.navbar-expand-lg {
// Background Gradient
background: linear-gradient(180deg, rgba(0, 133, 125, 0.00) 0%, rgba(0, 133, 125, 0.10) 100%), #FFF;
}
^^ Update styling to use root
Some very quick tests (Local file overwrites for netbox.css & rewriting colorMode.ts) seems to work.
Just want some clarity on why CSS is body instead of root and I might make a PR.
Just want some clarity on why CSS is body instead of root and I might make a PR.
That's before my time, so I'm not sure without more digging (probably in those related issues).
Looks like it's from @jeremystretch when restoring Darkmode functionality after removing it to work with Tabler: https://github.com/netbox-community/netbox/pull/14833/commits/cdba3085975ffc453d213ceb282c25f065d8de33
What I think happened is Darkmode was removed temporarily, then restored by assigning the new theme attribute to the body rather than root. From there future .SCSS contributions just referred to it by the body since that's where the attribute was being updated.
Heck another commit from ~2 weeks ago points out Tabler expects data-bs-theme to be using root rather than body as well:
https://github.com/netbox-community/netbox/blame/6efb258b9fe7281535a88ea729cdf5c64619684f/netbox/project-static/styles/overrides/_tabler.scss#L166-L179
@jeremystretch since I see you're a common contributor here could you comment on why it's on body rather than root?
I'm not much of a web dev so there might be some reason I don't know.
Edit: Just read the following in contributing.md. Sorry for pings!
Please avoid pinging members with @ unless they've previously expressed interest or involvement with that particular issue.