深色模式
Material UI 带有两种调色板模式:浅色(默认)和深色。
仅深色模式
您可以通过将 mode: 'dark'
添加到 createTheme()
辅助函数中,使您的应用程序默认使用深色主题——无论用户偏好如何
import { ThemeProvider, createTheme } from '@mui/material/styles';
import CssBaseline from '@mui/material/CssBaseline';
const darkTheme = createTheme({
palette: {
mode: 'dark',
},
});
export default function App() {
return (
<ThemeProvider theme={darkTheme}>
<CssBaseline />
<main>This app is using the dark mode</main>
</ThemeProvider>
);
}
将 mode: 'dark'
添加到 createTheme()
辅助函数会修改多个调色板值,如下面的演示所示
排版
palette.text.primary
#fff
palette.text.secondary
rgba(255, 255, 255, 0.7)
palette.text.disabled
rgba(255, 255, 255, 0.5)
按钮
palette.action.active
#fff
palette.action.hover
rgba(255, 255, 255, 0.08)
palette.action.selected
rgba(255, 255, 255, 0.16)
palette.action.disabled
rgba(255, 255, 255, 0.3)
palette.action.disabledBackground
rgba(255, 255, 255, 0.12)
背景
palette.background.default
#121212
palette.background.paper
#121212
分隔线
palette.divider
rgba(255, 255, 255, 0.12)
在 <ThemeProvider>
组件内部添加 <CssBaseline />
也将为应用程序的背景启用深色模式。
覆盖深色调色板
要覆盖默认调色板,请提供一个调色板对象,其中包含十六进制、RGB 或 HSL 格式的自定义颜色
const darkTheme = createTheme({
palette: {
mode: 'dark',
primary: {
main: '#ff5252',
},
},
});
了解有关调色板结构的更多信息,请参阅调色板文档。
系统偏好
一些用户通过其操作系统(无论是系统范围还是针对单个用户代理)设置了浅色或深色模式的偏好。以下部分解释了如何将这些偏好应用于应用程序的主题。
内置支持
使用 colorSchemes
节点构建具有多种配色方案的应用程序。内置的配色方案为 light
和 dark
,可以通过将值设置为 true
来启用它们。
浅色配色方案默认启用,因此您只需要设置深色配色方案
import { ThemeProvider, createTheme } from '@mui/material/styles';
const theme = createTheme({
colorSchemes: {
dark: true,
},
});
function App() {
return <ThemeProvider theme={theme}>...</ThemeProvider>;
}
当提供 colorSchemes
时,以下功能将被激活
- 根据用户偏好在浅色和深色配色方案之间自动切换
- 窗口选项卡之间的同步——在一个选项卡中对配色方案的更改将应用于所有其他选项卡
- 在配色方案更改时禁用过渡的选项
访问媒体 prefers-color-scheme
您可以将此偏好与 useMediaQuery
钩子和 prefers-color-scheme
媒体查询结合使用。
以下演示展示了如何检查用户在其操作系统或浏览器设置中的偏好
import * as React from 'react';
import useMediaQuery from '@mui/material/useMediaQuery';
import { createTheme, ThemeProvider } from '@mui/material/styles';
import CssBaseline from '@mui/material/CssBaseline';
function App() {
const prefersDarkMode = useMediaQuery('(prefers-color-scheme: dark)');
return <div>prefersDarkMode: {prefersDarkMode.toString()}</div>;
}
切换颜色模式
为了让您的用户可以在内置支持的模式之间切换,请使用 useColorScheme
钩子来读取和更新模式。
存储管理器
默认情况下,配色方案的内置支持使用浏览器的 localStorage
API 来存储用户的模式和方案偏好。
要使用不同的存储管理器,请创建一个具有此签名的自定义函数
type Unsubscribe = () => void;
function storageManager(params: { key: string }): {
get: (defaultValue: any) => any;
set: (value: any) => void;
subscribe: (handler: (value: any) => void) => Unsubscribe;
};
然后将其传递给 ThemeProvider
组件的 storageManager
属性
import { ThemeProvider, createTheme } from '@mui/material/styles';
import type { StorageManager } from '@mui/material/styles';
const theme = createTheme({
colorSchemes: {
dark: true,
},
});
function storageManager(params): StorageManager {
return {
get: (defaultValue) => {
// Your implementation
},
set: (value) => {
// Your implementation
},
subscribe: (handler) => {
// Your implementation
return () => {
// cleanup
};
},
};
}
function App() {
return (
<ThemeProvider theme={theme} storageManager={storageManager}>
...
</ThemeProvider>
);
}
禁用存储
要禁用存储管理器,请将 null
传递给 storageManager
属性
<ThemeProvider theme={theme} storageManager={null}>
...
</ThemeProvider>
禁用过渡
要立即在配色方案之间切换而无需过渡,请将 disableTransitionOnChange
属性应用于 ThemeProvider
组件
<ThemeProvider theme={theme} disableTransitionOnChange>
...
</ThemeProvider>
禁用双重渲染
默认情况下,当主题包含浅色和深色配色方案时,ThemeProvider
会重新渲染,以防止 SSR 水合不匹配。
要禁用此行为,请使用 noSsr
属性
<ThemeProvider theme={theme} noSsr>
如果您正在构建以下类型的应用程序,则 noSsr
非常有用
- 仅客户端应用程序,例如单页应用程序 (SPA)。此属性将优化性能并防止用户刷新页面时出现深色模式闪烁。
- 带有 Suspense 的服务器渲染应用程序。但是,您必须确保服务器渲染输出与客户端上的初始渲染输出匹配。
设置默认模式
当提供 colorSchemes
时,默认模式为 system
,这意味着应用程序在用户首次访问该站点时使用系统偏好。
要设置不同的默认模式,请将 defaultMode
属性传递给 ThemeProvider 组件
<ThemeProvider theme={theme} defaultMode="dark">
InitColorSchemeScript 组件
如果您使用 InitColorSchemeScript
组件来防止 SSR 闪烁,则必须使用与传递给 ThemeProvider
组件的值相同的值设置 defaultMode
<InitColorSchemeScript defaultMode="dark">
在深色模式下设置样式
使用 theme.applyStyles()
实用程序为特定模式应用样式。
我们建议使用此函数而不是检查 theme.palette.mode
来切换样式,因为它具有更多优势
- 它可以与 Pigment CSS 一起使用,这是我们内部的零运行时 CSS-in-JS 解决方案。
- 它通常更具可读性和可维护性。
- 它的性能略高,因为它不需要进行样式重新计算,但 SSR 生成样式的包大小更大。
用法
使用 styled
函数
import { styled } from '@mui/material/styles';
const MyComponent = styled('div')(({ theme }) => [
{
color: '#fff',
backgroundColor: theme.palette.primary.main,
'&:hover': {
boxShadow: theme.shadows[3],
backgroundColor: theme.palette.primary.dark,
},
},
theme.applyStyles('dark', {
backgroundColor: theme.palette.secondary.main,
'&:hover': {
backgroundColor: theme.palette.secondary.dark,
},
}),
]);
使用 sx
属性
import Button from '@mui/material/Button';
<Button
sx={[
(theme) => ({
color: '#fff',
backgroundColor: theme.palette.primary.main,
'&:hover': {
boxShadow: theme.shadows[3],
backgroundColor: theme.palette.primary.dark,
},
}),
(theme) =>
theme.applyStyles('dark', {
backgroundColor: theme.palette.secondary.main,
'&:hover': {
backgroundColor: theme.palette.secondary.dark,
},
}),
]}
>
Submit
</Button>;
API
theme.applyStyles(mode, styles) => CSSObject
为特定模式应用样式。
参数
mode
('light' | 'dark'
) - 样式应为其应用的模式。styles
(CSSObject
) - 包含要为指定模式应用的样式的对象。
覆盖 applyStyles
您可以覆盖 theme.applyStyles()
与自定义函数,以完全控制其返回的值。请查看源代码,以了解默认实现的工作原理,然后再覆盖它。例如,如果您需要该函数返回一个字符串而不是对象,以便可以在模板文字中使用它
const theme = createTheme({
cssVariables: {
colorSchemeSelector: '.mode-%s',
},
colorSchemes: {
dark: {},
light: {},
},
applyStyles: function (key: string, styles: any) {
// return a string instead of an object
return `*:where(.mode-${key}) & {${styles}}`;
},
});
const StyledButton = styled('button')`
${theme.applyStyles(
'dark', `
background: white;
`
)}
`;
Codemod
我们提供 codemod 以将您的代码库从使用 theme.palette.mode
迁移到使用 theme.applyStyles()
。您可以运行下面的每个 codemod 或一次运行所有 codemod。
npx @mui/codemod@latest v6.0.0/styled <path/to/folder-or-file>
npx @mui/codemod@latest v6.0.0/sx-prop <path/to/folder-or-file>
npx @mui/codemod@latest v6.0.0/theme-v6 <path/to/theme-file>
针对包含自定义
styleOverrides
的文件运行v6.0.0/theme-v6
。如果您没有自定义主题,请忽略此 codemod。
深色模式闪烁
问题
服务器渲染的应用程序在到达用户设备之前构建。这意味着它们在首次加载时无法自动调整为用户首选的配色方案。
以下是通常发生的情况
- 您加载应用程序并将其设置为深色模式。
- 您刷新页面。
- 应用程序短暂地以浅色模式(默认)显示。
- 然后在应用程序完全加载后切换回深色模式。
只要您的浏览器记住您的深色模式偏好,每次您打开应用程序时都会发生这种“闪烁”的浅色模式。
这种突然的变化可能会令人感到不适,尤其是在弱光环境中。它会使您的眼睛疲劳并打断您的体验,特别是如果您在此过渡期间与应用程序交互。
为了更好地理解这个问题,请查看下面的动画图像

解决方案:CSS 变量
解决此问题需要一种新颖的样式和主题方法。(请参阅此关于 CSS 变量支持的 RFC,以了解有关此功能实现的更多信息。)
对于需要使用 CSS 媒体 prefers-color-scheme
支持浅色和深色模式的应用程序,启用CSS 变量功能可以解决此问题。
但是,如果您希望能够手动切换模式,则避免闪烁需要 CSS 变量和 InitColorSchemeScript
组件的组合。请查看防止 SSR 闪烁部分以获取更多详细信息。