Safari 27.3 beta started darkening light websites that never implemented dark mode. If you have read about it this week, you have probably also read that the way out is color-scheme: light only.
That is correct. What nobody mentions is that only on its own is not a value, and the declaration most people reach for first is dropped by the parser without a word.
The grammar, from the spec
CSS Color Adjustment Level 1 defines the property like this:
Name: color-scheme Value: normal | [ light | dark | <custom-ident> ]+ && only? Initial: normal Read the value line carefully. only is behind && and a ?. It is an optional modifier that must accompany at least one scheme keyword. It is not an alternative to light or dark.
So this is valid, and means what you want:
:root { color-scheme: light only; } And this is not a valid declaration at all:
:root { color-scheme: only; } /* dropped */ No error, no warning, no visual difference on your machine. An invalid declaration is discarded at parse time and the property keeps its previous value, which is normal. The line is in your stylesheet, your diff, your review, and it is doing nothing.
What only actually does
The spec is one sentence: "Forbids the user agent from overriding the color scheme for the element."
The mechanism is in the algorithm for the used color scheme. If the user's preferred scheme is in your list, that is used. Otherwise:
if the user has indicated an overriding preference for their chosen color scheme, and the
onlykeyword is not present incolor-schemefor the element, the user agent must override the color scheme
only is the one token that makes that branch not fire. light alone tells the browser you support light. light only tells it that it may not overrule you.
Those two are a single word apart and nobody reviewing a stylesheet reads them as different things.
Why this was always going to happen
The same spec explains, in a note, why browsers had been leaving pages alone until now:
Because many pages were authored before color scheme support existed, user agents cannot automatically adapt the colors used in elements under their control, as it might cause unreadable color contrast with the surrounding page.
That was the constraint. A browser could not safely recolour a page that had said nothing, because it did not know enough. A vendor that believes it now knows enough, through analysing the page rather than guessing, is no longer bound by it. One of them has decided that.
The part that reaches you as a bug report
A recoloured page is a visible change with no visible cause. The user did not install anything, your deploy did not change, and the setting that did it is not one they think of as a setting.
And you cannot query your way out. Safari's own documentation says it "prevents websites from detecting when Adaptive Dark Mode has been applied", and that "JavaScript that queries CSS colors will get the original authored colors, not the transformed ones". So getComputedStyle reports your stylesheet, not the screen.
Which means the broken-looking line above fails in the worst possible way. You ship color-scheme: only, you check your own page, it looks right, because it always looked right on your machine. The declaration is invalid, the browser keeps recolouring, and the only instrument that would tell you is one the browser deliberately disabled.
Two minutes that settle it
The property reads back, even when the colours do not:
getComputedStyle(document.documentElement).colorScheme // "light only" -> parsed, you are opted out // "normal" -> your declaration was dropped That works because the computed value of color-scheme is, per the spec, "the keyword normal, or an ordered list of specified color scheme keywords". It is reporting what the parser kept, which is exactly the question. It is not reporting any colour, which is the question the browser will not answer.
Check the string, not the screen.
