Light and dark
Every color comes in a light and a dark version. Pages follow the device's setting until your app or your reader picks one, and any part of a page can have its own scheme.
The app's default
Use ColorScheme on the IzzyTheme in the head: Auto (the
default) follows the device, and Light or Dark holds one until the reader picks another.
<IzzyTheme Preset="ThemePreset.Standard" ColorScheme="ColorScheme.Dark" />
In plain HTML, data-ib-color-scheme="light" or "dark" on the html element
holds one too, but it also overrides the reader's choice below, so use IzzyTheme when readers can pick.
Let readers choose
Use ColorSchemeSwitch: a menu of System, Light and Dark for headers, a light/dark toggle, or all three side by side for a settings page.
Code
@* The three looks. They share the reader's choice (the ib-scheme cookie), so picking one here
changes the scheme of this site too. *@
<Row Gap="6" Align="Align.Center" Wrap>
<Stack Gap="2" Align="Align.Start">
<TextBlock Size="TextSize.Sm" Color="Color.Muted">Menu</TextBlock>
<ColorSchemeSwitch />
</Stack>
<Stack Gap="2" Align="Align.Start">
<TextBlock Size="TextSize.Sm" Color="Color.Muted">Toggle</TextBlock>
<ColorSchemeSwitch Variant="ColorSchemeSwitchVariant.Toggle" />
</Stack>
<Stack Gap="2" Align="Align.Start">
<TextBlock Size="TextSize.Sm" Color="Color.Muted">Segmented</TextBlock>
<ColorSchemeSwitch Variant="ColorSchemeSwitchVariant.Segmented" />
</Stack>
</Row>Static: The scheme changes at once, and other open tabs follow.
The choice is kept in the ib-scheme cookie. The IzzyTheme in the head reads
it on the server, so pages arrive in the reader's scheme with no flash: keep one there, even an empty
<IzzyTheme />. Reading the cookie takes AddIzzyBlazor().
With JavaScript off, each option is a link to an endpoint that MapIzzyBlazor() adds. It saves the
cookie and sends the reader back.
builder.Services.AddIzzyBlazor();
// ...
app.MapIzzyBlazor();
On an interactive page, @bind-Value gives you the choice as a ColorScheme:
Auto for System, Light or Dark.
A scheme for part of a page
Use ColorScheme on Box, Stack, Card and the other layout
components, or a part of the app layout: Dark
for a dark sidebar or header in a light app, Light, or Inverse for the opposite of the
page, even when the page follows the device.
Preview
Dark
ColorScheme.Dark
Inverse
ColorScheme.Inverse, the opposite of the page
Code
@* A dark part of a light page, and one that's always the opposite of the page (Inverse). Every
token switches inside, so text, buttons and badges keep their contrast. *@
<Grid Columns="new() { Base = 1, Sm = 2 }" Gap="4" Grow>
<Card Title="Dark" Description="ColorScheme.Dark" ColorScheme="ColorScheme.Dark">
<Row Gap="2" Wrap Align="Align.Center">
<Button>Deploy</Button>
<Button Variant="ButtonVariant.Outline" Accent="Accent.Neutral">Logs</Button>
<Badge Status="Status.Warning">Pending</Badge>
</Row>
</Card>
<Card Title="Inverse" Description="ColorScheme.Inverse, the opposite of the page" ColorScheme="ColorScheme.Inverse">
<Row Gap="2" Wrap Align="Align.Center">
<Button>Deploy</Button>
<Button Variant="ButtonVariant.Outline" Accent="Accent.Neutral">Logs</Button>
<Badge Status="Status.Success">Live</Badge>
</Row>
</Card>
</Grid>
Every color switches inside it, so text, links, buttons, badges, fields, focus rings and menus opened from it keep
their contrast. Bg still applies on top: Bg="Color.Fill" is that scheme's
container shade. On your own elements, data-ib-color-scheme="dark", "light" or
"inverse" does the same.
Your colors in both schemes
Write a color as a light-dark() pair and one value covers both schemes, including parts of a page
with their own:
.release-band {
background: light-dark(#fff7ed, #2a1a0c);
border-color: light-dark(#fed7aa, #7c2d12);
}Give a color the same value twice, or a plain color, if it shouldn't change with the scheme. Keep text at 4.5:1 on what it sits on in both.
Next steps
- Tokens and customizing: every color as a CSS variable.
- ColorSchemeSwitch: the full API.