Hoewel de eigenschap color-scheme vaker wordt ingesteld op de root, kan deze ook worden ingesteld op afzonderlijke elementen om ze een ander kleurenschema te geven dan de rest van de pagina.
Dit kan handig zijn voor componenten die altijd in een specifiek kleurenschema moeten worden bekeken (bijvoorbeeld altijd in de donkere of lichte modus).
Voorbeelden van use cases zijn:
- Elementen die om esthetische redenen vaak in de donkere modus staan, zelfs op pagina's in de lichte modus, zoals codeblokken, mediaspelers en fotogalerijen
- Gebieden met media die zijn ontworpen voor een lichte achtergrond (bijvoorbeeld afbeeldingen, video's, illustraties, afdrukvoorbeelden) kunnen worden ingesteld op de lichte modus, zelfs als de rest van de pagina in de donkere modus staat.
- Elementen waarvan het kleurenschema wordt beheerd door een instelling op gebruikersniveau, zoals componentvoorbeelden
- Insluitingen die niet zowel de lichte als de donkere modus ondersteunen
- Ontwerptools, kaarten, visualisaties, games, enzovoort.
Wanneer moet je kleuren wijzigen en wanneer moet je color-scheme afdwingen?
Niet elk element dat lichtere tekst op een donkerdere achtergrond gebruikt in de lichte modus of donkerdere tekst op een lichtere achtergrond in de donkere modus, heeft een andere color-scheme nodig.
Een primaire knop kan bijvoorbeeld blauw worden weergegeven met witte tekst in de lichte modus, maar dat rechtvaardigt geen color-scheme: dark.
Als vuistregel geldt dat elementen die een andere color-scheme gebruiken, meestal complexe oppervlakken zijn die hun eigen visuele context bepalen, in plaats van eenvoudige ondiepe containers.
Als je overweegt een andere color-scheme te gebruiken voor een element, stel jezelf dan de volgende vragen:
- Moet de ingebouwde browser-UI die niet op een andere manier is aangepast (bijvoorbeeld formulierbediening, scrollbalken, enzovoort) dat kleurenschema gebruiken of zich aanpassen aan het kleurenschema van de pagina? -> if the former, don't use
color-scheme. - Moeten
light-dark()-kleuren worden opgelost zoals voor de rest van de pagina of op basis van de overschrijving? -> if the former, don't usecolor-scheme. - Moeten afstammelingen in die
color-schemestaan? Als dat niet het geval is, gebruik jecolor-schemeniet.
Basisimplementatie
Componentspecifieke overschrijvingen worden meestal (maar niet noodzakelijkerwijs) gebruikt op pagina's die ook meerdere kleurenschema's ondersteunen via een algemene color-scheme.
Ga naar Donkere modus voor meer informatie over hoe je de donkere modus voor de hele pagina implementeert.
Zodra er een paginabrede color-scheme is ingesteld en je kleurtokens gebruikt die daar gevoelig voor zijn (bijvoorbeeld via light-dark()), kun je color-scheme instellen voor specifieke componenten om de kleurmodus voor die substructuur te overschrijven:
pre, code, .dark {
color-scheme: dark;
}
Sommige browsers passen componenten automatisch aan een ander kleurenschema aan.
Als je het aangegeven kleurenschema in alle gevallen wilt afdwingen, gebruik je only, dus color-scheme: only dark; in plaats van color-scheme: dark;.
Niet-kleurwaarden aanpassen
light-dark() werkt op dit moment alleen voor kleuren.
Praktische tips
- VERPLICHT: Stel
color-schemeniet in voor elementen zonder achtergrond, omdat je dan het risico loopt dat achtergrond- en tekstkleurparen uit verschillende kleurenschema's worden gemengd, waardoor de tekst onleesbaar wordt. - OPTIONEEL: Hoewel het makkelijker is om dezelfde kleurparen te hergebruiken als de paginabrede donkere modus, kunnen we verschillende kleurparen definiëren voor deze componenten. We willen bijvoorbeeld dat een component in de donkere modus die wordt gebruikt op een pagina in de lichte modus, iets minder donker is dan wanneer dezelfde component in de donkere modus wordt gebruikt op een pagina die helemaal in de donkere modus staat.
Bekende problemen om rekening mee te houden
Belangrijk aandachtspunt: overname van light-dark()-kleuren
light-dark() wordt omgezet op het moment van de berekende waarde.
Dit betekent dat overgenomen <color>-eigenschappen die zijn ingesteld op een light-dark()-kleur, maar één van de twee kleuren doorgeven aan hun afstammelingen, niet de light-dark()-expressie zelf.
Bijvoorbeeld:
- Ingebouwde kleureigenschappen die worden overgenomen, zoals
color,accent-color,fill,stroke,text-shadow,caret-color - Geregistreerde overerfbare aangepaste eigenschappen met
syntax: <color>eninherits: true - Een andere
<color>-property ingesteld opinherit
Dit betekent dat je het volgende moet doen:
- Registreer aangepaste eigenschappen die bedoeld zijn voor designtokens (bijv.
--surface-color) NIET als<color>. Tokens moeten hunlight-dark()-expressie live houden, zodat afstammelingen ze opnieuw kunnen oplossen onder een anderecolor-scheme. - Als je
color-schemeinstelt voor een element, geef je alle overgenomen<color>-eigenschappen opnieuw op die misschien zijn ingesteld oplight-dark()-waarden (rechtstreeks of via ontwerptokens), zelfs als dat dezelfde ontwerptoken is. - Gebruik
inheritNIET voor<color>-property's voor elementen met eencolor-scheme-overschrijving (je kunt dit wel gebruiken voor de onderliggende elementen). - Gebruik WEL geregistreerde
<color>-property's voor de tegenovergestelde use case: als je bewust een momentopname wilt maken van de opgeloste kleur van de bovenliggende property en wilt voorkomen dat deze opnieuw wordt opgelost onder decolor-schemevan de onderliggende property. Bijvoorbeeld om de pagina-achtergrond vast te leggen en ergens anders te gebruiken. - Als je een kleur wilt animeren, gebruik je een afzonderlijke
@property-geregistreerde<color>-property voor het element dat wordt geanimeerd (registratie is vereist voor kleurinterpolatie). Dit is geen designtoken, maar een animatiedoel per element, dus dit is niet in strijd met de bovenstaande regel.
Voorbeeld:
:root {
--accent-color: light-dark(blue, skyblue);
--surface-color: light-dark(white, #222);
--text-color: light-dark(#111, white);
color-scheme: light dark;
accent-color: var(--accent-color);
color: var(--text-color);
}
body {
/* --surface-color dynamically switches despite being inherited because --surface-color is not registered */
background: var(--surface-color);
}
pre, code {
color-scheme: dark;
background: var(--surface-color);
/* Without this, accent-color would be blue, not skyblue! */
accent-color: var(--accent-color);
/* Without this, text-color would be #111, not white! */
color: var(--text-color);
}
Problemen om rekening mee te houden als je color-scheme gebruikt
- Chrome en Firefox respecteren
color-schemevoor iframes: ze geven ingesloten pagina's weer in het juiste kleurenschema en passen de mediaqueryprefers-color-schemevan de ingesloten pagina aan decolor-schemevan de insluitingscontext aan. Safari doet dit niet en herleidtprefers-color-schemenaar de systeeminstelling, zelfs binnen iframes.- Als je zowel de bovenliggende pagina als het iframe beheert: Geef het kleurenschema van de bovenliggende pagina expliciet door aan het iframe, via een URL-parameter (
?theme=dark) op het moment dat het iframe wordt gemaakt of viapostMessage()(waarmee je ook kunt reageren op wijzigingen tijdens de runtime). Stel in het iframe een klasse in op<html>(en/ofcolor-schemeop:root) op basis van dat signaal in plaats van te vertrouwen opprefers-color-scheme. - Als je alleen de ingesloten pagina beheert: Er is geen betrouwbare manier om de
color-schemevan de insluitingscontext te detecteren vanuit het iframe in Safari. Maak een expliciete themaparameter beschikbaar in je insluit-API (bijvoorbeeld een querytekenreeks ofpostMessage-protocol) en documenteer deze voor insluiters.
- Als je zowel de bovenliggende pagina als het iframe beheert: Geef het kleurenschema van de bovenliggende pagina expliciet door aan het iframe, via een URL-parameter (
Reservestrategieën
Fallbacks en browserondersteuning voor kleurenschema
De property color-scheme is progressive enhancement.
Browsers die dit niet ondersteunen, negeren deze property en gebruiken de standaard UI voor de lichte modus.
Als je je wilt aanpassen aan de voorkeuren van de gebruiker in oudere browsers, gebruik je prefers-color-scheme-mediaquery's om verschillende kleuren te bieden als de donkere modus de voorkeur heeft.
- Gebruik de mediaquery om aangepaste eigenschappen aan te zetten op
:rootofhtml. - Gebruik de mediaquery niet voor afzonderlijke componenten, tenzij de component een heel specifiek type aanpassing voor de donkere modus vereist dat verder gaat dan kleuren.
:root {
/* Define brand colors for each mode */
--color-brand-light: #0056b3;
--color-brand-dark: #00e5ff;
--color-brand: var(--color-brand-light);
/* MANDATORY: Fallback for browsers without light-dark support */
@media (prefers-color-scheme: dark) {
--color-brand: var(--color-brand-dark);
}
/* Ignored in older browsers */
color-scheme: light dark;
}
button.primary {
background-color: var(--color-brand);
}
Fallbacks en browserondersteuning voor light-dark()
Voor browsers die color-scheme ondersteunen maar nog niet light-dark(), moeten lichte en donkere versies van kleuren eerst worden gedefinieerd als aangepaste eigenschappen. De mediaquery prefers-color-scheme moet worden gebruikt om kleuren in te stellen voor de betreffende modus, zoals in het voorbeeld hieronder:
:root {
/* Define browser UI accent color for each mode */
--brand-accent-light: #0056b3;
--brand-accent-dark: #00e5ff;
--accent-color: var(--brand-accent-light);
/* MANDATORY: Fallback for browsers without light-dark support */
@media (prefers-color-scheme: dark) {
--accent-color: var(--brand-accent-dark);
}
/* OPTIONAL: use light-dark() for more control of built-in UI colors */
@supports (color: light-dark(white, black)) {
--accent-color: light-dark(var(--brand-accent-light), var(--brand-accent-dark));
}
/* MANDATORY: Automatically adapt native UI to user system preferences */
color-scheme: light dark;
/* Example inherited color property */
accent-color: var(--accent-color);
}
pre, code {
color-scheme: dark;
/* **Mandatory**: any inherited color properties must be set again, even if to the same design tokens */
accent-color: var(--accent-color);
}