Skip to content

fix: flash of white while loading page in dark mode on Firefox #8836

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 5 commits into
base: master
Choose a base branch
from

Conversation

adil192
Copy link

@adil192 adil192 commented Jun 27, 2025

  • This PR adds a <meta name="color-scheme" content="light dark"/> so the browser's default dark mode can be applied before the css is loaded (https://web.dev/articles/color-scheme)
  • When the css is loaded, that meta tag is overridden with color-scheme: dark; or light as needed.

  • I’ve reviewed the contributor guide and applied the relevant portions to this PR.
    (I'm unsure if the pubspec package version needs increasing)
Contribution guidelines:

Note that many Dart repos have a weekly cadence for reviewing PRs - please allow for some latency before initial review feedback.

@sigurdm sigurdm requested a review from isoos June 27, 2025 11:15
@isoos
Copy link
Collaborator

isoos commented Jun 27, 2025

The dark mode theme and color is controlled via a CSS variable that is set after the site's JavaScript is being loaded. I don't see how this would reduce any flash of white - could you please provide more details on how this would change any of the behavior?

E.g. what is the benefit here instead e.g. styling the .light-theme and .dark-theme styles with media selectors instead?

@adil192
Copy link
Author

adil192 commented Jun 27, 2025

When the browser starts loading the page, it loads the html first before the css. So having the color-scheme defined in the html means the browser can apply a dark background sooner, instead of having to wait for the css to load.

https://developer.mozilla.org/en-US/docs/Web/CSS/color-scheme:

Along with the above CSS, also include the <meta name="color-scheme"> HTML <meta> tag in the <head>, before any CSS style information, to inform user agents about the preferred color scheme, helping prevent unwanted screen flashes during the page load.


The dark mode theme and color is controlled via a CSS variable that is set after the site's JavaScript is being loaded

The majority of users will probably use the same theme as their system, so the color-scheme tag works for this.
If the user uses the website's button to switch themes, then they will still see a white/dark flash before the css kicks in.

@isoos
Copy link
Collaborator

isoos commented Jun 27, 2025

Upon closer inspection, I see a difference between pub.dev and dartdoc in this regard: pub.dev blocks the rendering until the variable is read and the main style is set, while dartdoc seems to not block it, and the pub.dev embedding of the dartdoc pages doesn't fix that either. I prefer to fix that in dartdoc (or its pub.dev embedding) the same way we use it on the rest of pub.dev, to preserve the consistency - by blocking the rendering for now.

As a follow-up change, we should also support media selectors, and after that, we should consider if/how the feature should work with non-blocking rendering. I wouldn't mind having the metadata here on the page (after the above changes), but I don't think it will help for those who leave their OS theme settings on default but switch their theme on pub.dev.

@adil192
Copy link
Author

adil192 commented Jun 27, 2025

Hmm yes I see the issue. When the page is first loaded, it's served with body.light-mode (subject to an experimental flag at build time) meaning this meta tag's effectiveness is limited: the page starts dark thanks to the meta tag, then the light-mode site is loaded, then the js sets it to dark mode again (as per the toggle).

d.element(
'body',
classes: [
...?bodyClasses,
requestContext.experimentalFlags.isDarkModeDefault
? 'dark-theme'
: 'light-theme',

In Chrome, this seems to work fine as the js blocks the rest of the document from getting parsed & rendered.
But in Firefox, the page still renders body.light-mode even while the js is blocking parsing.

I've added <script ... blocking="render"> to explicitly request the blocking behaviour we want, though it doesn't fix the Firefox behaviour since it isn't supported on firefox yet.

I've then added a temporary loading-theme class which is removed by dark-init.js. The loading-theme class tells the browser to use the system brightness. This fully fixes the flash of white in Firefox!

Note:

  • This also needs adding to dartdoc too, but I assume the minified third_party dartdoc files come from another repo and so need to be edited externally.
  • And the goldens still need regenerating before this gets merged.
  • Inlining dark-init.js into the html page may yield a small loading time improvement since the browser doesn't need to fetch a second file before it can render. Would it be worth making a separate PR for this?

@adil192 adil192 changed the title fix: reduce flash of white while loading page in dark mode fix: flash of white while loading page in dark mode on Firefox Jun 27, 2025
@adil192
Copy link
Author

adil192 commented Jun 27, 2025

Perhaps a better solution long-term is to initially load the body without .light-theme or .dark-theme, and use this css with the light-dark function:

// <meta name="color-scheme" content="light dark"/>
body.light-theme { color-scheme: light; }
body.dark-theme { color-scheme: dark; }

body {
  --pub-neutral-bgColor: light-dark(var(--pub-color-white), var(--pub-color-darkBlack));
  --pub-neutral-borderColor: light-dark(var(--pub-color-smokeWhite), var(--pub-color-darkGunmetal));
  --pub-neutral-textColor: var(--dash-surface-fgColor);
  // etc
}

By default, this will use the system theme. Then the script can add .light-theme or .dark-theme to body to override the theme.
However, this is a larger change so I'll ask here before implementing it

@isoos
Copy link
Collaborator

isoos commented Jun 27, 2025

@adil192 I'm more comfortable with a very narrow fix that I've implemented in #8837, and I suggest we close this PR. An important reason for that is we have some plans to bring the dartdoc and pub.dev styles and layout closer, and while those plans are still in progress, I wouldn't want to change too much things all at once. However, I think we should keep track of the suggestions you were making here - would you mind creating an issue or two about them, describing why the metadata or anything else would be important (if it still is after a fix)?

@isoos
Copy link
Collaborator

isoos commented Jun 30, 2025

Upon further reading about the <meta name="color-scheme"> internals, I think we don't want to use it for now. Given the current site setup (and the fix in #8837), and unless we change significant portions, the support of media queries in dartdoc on top of the current theme switcher seems to be the missing piece, especially with the level of theme control we want to (somewhat) synchronize with other Dart-team sites. I've opened dart-lang/dartdoc#4069 to track that in dartdoc.

I'm a bit undecided whether the color-scheme: light|dark CSS property would add much if/when the media queries are already supported. I've created a tracking issue for it: #8838

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants