Dark Mode 暗色模式
能力介绍
🤩 Semi 的默认主题或任意通过 Semi DSM 配置的定制主题都自带了亮色模式与暗色模式,可以方便地进行切换。
🌒 Semi 也支持在页面的局部范围使用亮/暗色模式。
推荐设置
Semi 会自动在 body 元素上挂载全局色盘,我们内置了一些常用的 CSS Token,详细的 Token 详情可查阅 设计变量
我们推荐你在 body 上配置 color
、background-color
, 你的业务组件可从 body 自动继承获得默认的背景色、文本颜色,自适应亮/暗色切换
css
// css
body {
color: var(--semi-color-text-0);
background-color: var( --semi-color-bg-0);
}
如何切换
Semi 暗色模式的切换是通过给 body
添加属性 [theme-mode='dark']
来实现的(我们在 body 下同时挂载了两套色盘)。你可以使用任何你喜欢的方式来进行切换。比如:
jsx
const body = document.body;
if (body.hasAttribute('theme-mode')) {
body.removeAttribute('theme-mode');
} else {
body.setAttribute('theme-mode', 'dark');
}
这里也有一个🌰:
Invalid vnode type when creating vnode: undefined. at <Repl>
demoApp.vue
demo.tsx
tsconfig.json
Import Map
xxxxxxxxxx
11
7
24
import { h } from 'vue';
import { Button } from '@kousum/semi-ui-vue';
function Demo() {
const switchMode = () => {
const body = document.body;
if (body.hasAttribute('theme-mode')) {
body.removeAttribute('theme-mode');
// 以下这行代码,window.setMode仅用于当通过本Demo切换时,通知Semi官网Header记录更新当前模式(只用于演示)。在您的代码里无需存在。
window.setMode('light');
} else {
body.setAttribute('theme-mode', 'dark');
window.setMode('dark');
}
};
return (
<Button
onClick={switchMode}
>
Switch Mode
</Button>
);
}
Show Error
Auto Save
和系统主题保持一致
如果你希望页面的亮色/暗色模式能自动和系统主题保持一致,可以参考 prefers-color-scheme 属性。该属性目前处于实验阶段,请留意浏览器兼容性 (Chrome >= 76, Safari >= 12.1) 及未来可能发生的改变。
macOS 下的系统主题可以通过 系统偏好设置 -> 通用 -> 外观
来配置。
由于我们不建议直接修改 npm 主题包的内容,你可以通过 JS 的方式监听该属性的变化,这里也有一个🌰:
jsx
const mql = window.matchMedia('(prefers-color-scheme: dark)');
function matchMode(e) {
const body = document.body;
if (e.matches) {
if (!body.hasAttribute('theme-mode')) {
body.setAttribute('theme-mode', 'dark');
}
} else {
if (body.hasAttribute('theme-mode')) {
body.removeAttribute('theme-mode');
}
}
}
mql.addListener(matchMode);
局部暗色/亮色模式
Semi 2.0 原生支持局部暗色/亮色模式。使用时,在顶级元素上添加 .semi-always-dark
或 .semi-always-light
类,这个类下的组件会使用对应模式的颜色变量。
注意:由于弹出层默认是插入到 body 中,局部暗色/亮色对弹出层元素不生效。若你希望对弹出层也生效,应当使用 getPopupContainer 将弹出层插入节点置于你挂载 `.semi-always-dark` 或 `.semi-always-light`类名的元素内部
darkDemoApp.vue
darkDemo.tsx
tsconfig.json
Import Map
xxxxxxxxxx
11
7
339
import type { ComponentObjectPropsOptions } from 'vue';
import { defineComponent, Fragment, ref } from 'vue';
import {
Avatar,
Badge,
Breadcrumb,
Button,
Layout,
LayoutContent,
LayoutFooter,
LayoutHeader,
LayoutSider,
Nav,
NavFooter,
NavHeader,
Pagination,
Popover,
Rating,
Row,
Steps,
StepsStep,
Tag,
Timeline,
TimelineItem,
Tooltip,
} from '@kousum/semi-ui-vue';
import {
IconBell,
IconBytedanceLogo,
IconCamera,
IconEdit,
IconHelpCircle,
IconHistogram,
IconHome,
IconList,
IconLive,
IconSemiLogo,
IconSetting,
} from '@kousum/semi-icons-vue';
interface darkDemoProps {
name?: string;
}
export const vuePropsType: CombineProps<darkDemoProps> = {
name: String,
};
const darkDemo = defineComponent<darkDemoProps>(
(props, {}) => {
const mode = ref('semi-always-dark');
const switchMode = () => {
mode.value = mode.value === 'semi-always-dark' ? 'semi-always-light' : 'semi-always-dark';
};
return () => {
const rowStyle = { margin: '16px 10px' };
const badgeStyle = {
width: '42px',
height: '42px',
borderRadius: '4px',
display: 'inline-block',
Show Error
Auto Save