Skip to content

fix(w3c/style): put the dark stylesheet last on export so the theme toggle works - #5436

Merged
marcoscaceres merged 6 commits into
mainfrom
fix/dark-css-last
Sep 2, 2026
Merged

fix(w3c/style): put the dark stylesheet last on export so the theme toggle works#5436
marcoscaceres merged 6 commits into
mainfrom
fix/dark-css-last

Conversation

@marcoscaceres

@marcoscaceres marcoscaceres commented Aug 27, 2026

Copy link
Copy Markdown
Contributor

Refs #5200, and fixes a regression from #5408. On an exported spec that never opted into dark mode the theme toggle did nothing: styleMover was subscribed for the maturity stylesheet unconditionally but for dark.css only when the spec had opted in, so on save the maturity sheet moved past it and won the cascade. The dark sheet now moves for every spec, and its disabled and media state is restored on export, so a document saved while the reader had dark selected no longer ships a permanently dark spec.

Two existing tests asserted the old order and were rewritten.

This makes dark mode reachable where it previously did nothing, which exposes that several of ReSpec's own stylesheets are not dark-ready yet. Those are separate PRs and no release should go out before they land.

Written with AI: this change was generated by Claude. Per AI_POLICY.md.

Proof: the same source exported with the base build and with this branch. Without the fix dark.css lands before W3C-ED and enabling it changes nothing; with the fix it lands last and the toggle works. Marcos then confirmed it manually on exported specs: #5436 (comment)

@marcoscaceres
marcoscaceres requested a lite review from Copilot August 27, 2026 09:12
@marcoscaceres
marcoscaceres marked this pull request as ready for review August 27, 2026 09:14
@marcoscaceres
marcoscaceres requested a review from deniak August 27, 2026 09:16

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Fixes exported-document stylesheet ordering in the W3C profile so the TR theme toggle (from W3C fixup.js) actually switches to dark mode by ensuring the dark stylesheet ends up last in <head> on export.

Changes:

  • Always register the export-time styleMover for dark.css, not only when the spec opts into dark mode.
  • Update integration/exporter tests to assert the corrected stylesheet order on export.

Reviewed changes

Copilot reviewed 3 out of 3 changed files in this pull request and generated 1 comment.

File Description
src/w3c/style.js Always moves dark.css to the end of <head> during export so it wins the cascade when enabled.
tests/spec/w3c/style-spec.js Updates W3C style export assertions to expect dark stylesheet last.
tests/spec/core/exporter-spec.js Updates exporter test to expect dark.css after the maturity-level W3C stylesheet.
Suppressed comments (1)

src/w3c/style.js:145

  • The comment mentions that the earlier mover puts base.css at the end of head on export, but the mover above actually targets finalStyleURL (the maturity-level stylesheet, which is often W3C-*, not base.css). Updating the wording would avoid misleading future readers about what is being reordered.
  );
  // Make sure the W3C stylesheet is the last stylesheet, as required by W3C Pub Rules.
  sub("beforesave", styleMover(finalStyleURL));

  // Add color scheme meta tag and style

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Comment thread tests/spec/core/exporter-spec.js Outdated

Copilot AI commented Aug 27, 2026

Copy link
Copy Markdown
Contributor

One or more custom setup steps configured for this repository failed during this Copilot code review run:

Run {

Setup steps run before each review. If the review above is missing context, or no review was posted at all, the failing step above may be the cause. See the workflow run for failure details, fix your setup steps configuration, and re-request a review.

Note

You can configure setup steps for Copilot code review separately from Copilot cloud agent with a copilot-code-review.yml file. Read the docs for details.

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 3 out of 3 changed files in this pull request and generated no new comments.

Copilot AI commented Aug 27, 2026

Copy link
Copy Markdown
Contributor

One or more custom setup steps configured for this repository failed during this Copilot code review run:

Run {

Setup steps run before each review. If the review above is missing context, or no review was posted at all, the failing step above may be the cause. See the workflow run for failure details, fix your setup steps configuration, and re-request a review.

Note

You can configure setup steps for Copilot code review separately from Copilot cloud agent with a copilot-code-review.yml file. Read the docs for details.

@marcoscaceres

Copy link
Copy Markdown
Contributor Author

Confirmed manually locally that this works as expected on exported specs.

@deniak

deniak commented Aug 27, 2026

Copy link
Copy Markdown
Contributor

@marcoscaceres I understand that PR addresses the issue where the dark mode isn't working as expected of exported documents such as https://w3c.github.io/wcag/guidelines/.

That said, there seems to be a problem with the respec source documents. I tried that PR with the guidelines source document (see https://nix.w3.org/~denis/respec/guidelines/) and while it's working fine on firefox, chrome 151 renders the spec sometimes in light mode and some other times in dark mode (I have the toggle set to auto). There may be some kind of race condition...

@marcoscaceres

Copy link
Copy Markdown
Contributor Author

Yep, that’s being addressed an a follow up. Coming in after this PR.

@kfranqueiro

Copy link
Copy Markdown
Contributor

I observe the same issue as Denis, specifically when ReSpec is run client-side (not when viewing an already-processed document). Amusingly, it is somehow always wrong:

  • When my stored setting is dark or auto (with my system set to dark), it always initially shows light mode
  • When my stored setting is light mode, it always shows dark mode.

Yep, that’s being addressed an a follow up. Coming in after this PR.

Does that branch exist yet so we can get an idea of its complexity? Otherwise it doesn't seem to make much sense to approve this PR that is visibly broken...

Moreover, how many more upcoming PRs will there be? And why are we addressing a regression caused by a PR that did not fix anything by adding more complexity (and maybe more regressions), rather than by reverting the one PR in question?

This makes dark mode reachable where it previously did nothing, which exposes that several of ReSpec's own stylesheets are not dark-ready yet. Those are separate PRs and no release should go out before they land.

By this logic, 37.3.3+ should not have released with #5408 to begin with. It is also unclear to me, did these issues not already exist in earlier versions when opted into dark mode?

So far, 11 documents have been published to w3.org/TR/ since Monday that exhibit the broken theme toggle (out of 32 total). That number will only increase until it is resolved. This is why I immediately advocated for reverting #5408, which could have limited the number of affected publications to 1 or 2.

There is also still the core issue of #5408 having spontaneously changed default behavior in a patch release, and #5437 plans to move further in that direction. A change this major should only happen after all of the following:

  • dark mode styles have been fully vetted, including for accessible color contrast
  • advance notice is given to spec editors to adjust custom styles accordingly
    • Although if we give editors this chance, they might as well opt in by themselves via the meta tag to begin with in order to test the styles, which would seemingly obviate any need for these changes?
  • docs are updated (currently, respec.org still documents dark mode support as opt-in via meta tag)

@marcoscaceres

Copy link
Copy Markdown
Contributor Author

@deniak @kfranqueiro The race is real, it reproduces on main, and it is not caused by
this PR. The fix is #5439: it sets disabled on the dark stylesheet link before inserting
the link, rather than assigning the property on the statement after. A write that lands
mid-fetch leaves Chrome applying the sheet anyway and then dropping it on the next write,
so the theme you get depends on whether dark.css has arrived. Firefox always has it in
time, which is why it looked Chrome-only. Kenneth, on complexity: the change in
style.js is three lines in and six out, and the rest of that PR is the regression test.

On whether the dark styles were already broken before #5408: you are right, they were.
The dark media queries in var.css.js, algorithms.css.js and cddl.css.js predate it,
so any spec that opted in through the meta tag has had them all along. #5408 did not
create those defects, it made them reachable for everyone. That cuts both ways: it is an
argument for fixing them, and it also means reverting #5408 would not fix them for the
specs that already opted in.

The docs point is correct and unfixed too: respec.org still documents dark mode as
opt-in via the meta tag.

On reverting #5408: I would rather fix these. A revert does stop the race, by taking the
link back out again, but it also restores #5200, where the toggle silently never appears
on a light-only spec. And it does nothing for the documents already published: those are
static, so they need republishing either way. That leaves the revert case resting on
limiting future publications, which #5436 and #5439 do as well, without giving up the
toggle.

Your three preconditions are reasonable and I am not going to pretend they were met. The
styles are not fully vetted, editors got no notice, and the docs are stale. I would rather
work through them than revert: the docs I can fix now, the component styles need their own
PR, and #5437 waits until both are done.

@deniak

deniak commented Sep 1, 2026

Copy link
Copy Markdown
Contributor

@deniak @kfranqueiro The race is real, it reproduces on main, and it is not caused by this PR. The fix is #5439: it sets disabled on the dark stylesheet link before inserting the link, rather than assigning the property on the statement after. A write that lands mid-fetch leaves Chrome applying the sheet anyway and then dropping it on the next write, so the theme you get depends on whether dark.css has arrived. Firefox always has it in time, which is why it looked Chrome-only. Kenneth, on complexity: the change in style.js is three lines in and six out, and the rest of that PR is the regression test.

On whether the dark styles were already broken before #5408: you are right, they were. The dark media queries in var.css.js, algorithms.css.js and cddl.css.js predate it, so any spec that opted in through the meta tag has had them all along. #5408 did not create those defects, it made them reachable for everyone. That cuts both ways: it is an argument for fixing them, and it also means reverting #5408 would not fix them for the specs that already opted in.

The docs point is correct and unfixed too: respec.org still documents dark mode as opt-in via the meta tag.

On reverting #5408: I would rather fix these. A revert does stop the race, by taking the link back out again, but it also restores #5200, where the toggle silently never appears on a light-only spec. And it does nothing for the documents already published: those are static, so they need republishing either way. That leaves the revert case resting on limiting future publications, which #5436 and #5439 do as well, without giving up the toggle.

@kfranqueiro and I have reviewed the PRs and confirm #5439 fixes the issue with chrome. Can you merge #5436 and #5439 so we don't end up with a conflict? It will also be easier to follow the changes if there's only one PR.

Your three preconditions are reasonable and I am not going to pretend they were met. The styles are not fully vetted, editors got no notice, and the docs are stale. I would rather work through them than revert: the docs I can fix now, the component styles need their own PR, and #5437 waits until both are done.

Thank you for addressing my request about allowing the editors to opt-in. I initially thinking it would be easier to keep the old behavior (which is adding the <meta name="color-scheme" content="light dark”> to enable dark mode). This way we wouldn't need to edit the current specs that are not compatible with dark mode.

I'm willing to contact the editors to see how they feel about enabling dark mode support for all specs and point them to #5437 that adds the new config property.
Enabling dark mode by default would be great and I should probably have pushed more fixing the specs that are compatible yet.

@kfranqueiro

kfranqueiro commented Sep 1, 2026

Copy link
Copy Markdown
Contributor

On reverting #5408: I would rather fix these. A revert does stop the race, by taking the link back out again, but it also restores #5200, where the toggle silently never appears on a light-only spec.

This statement does not accurately describe #5200. The document that it was reported against was already opted into dark mode using the meta tag, and the report was that the theme controls did render, but didn't work - which I could never reproduce, even when using the versions of ReSpec and matf that were current at the time of the report.

As far as I could tell, there was nothing for #5408 to fix, which is why I suggested reverting it instead of adding more. (I realize there may be other motivations for moving in that direction.)

@marcoscaceres

Copy link
Copy Markdown
Contributor Author

Specref outage is also blocking us 😢 all the bots are sad.

@marcoscaceres marcoscaceres added the AI Contains AI-generated logic; see AI_POLICY.md label Sep 2, 2026
marcoscaceres and others added 5 commits September 2, 2026 22:56
…oggle works

Co-Authored-By: Claude <noreply@anthropic.com>
fixup.js drives the link live and both disabled and media are reflected attributes, so a document saved while the reader had dark selected exported an enabled, unconditional dark sheet. Now that the sheet is last in head it would win, rendering dark for everyone.

Co-Authored-By: Claude <noreply@anthropic.com>
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
@marcoscaceres
marcoscaceres merged commit c062116 into main Sep 2, 2026
9 checks passed
@marcoscaceres
marcoscaceres deleted the fix/dark-css-last branch September 2, 2026 13:58
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

AI Contains AI-generated logic; see AI_POLICY.md

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants