Design Collaboration · Dark Mode

Dark Mode

Dark mode

🤩 Every Semi color variable has a light and a dark value, which can be easily switched.
🌒 Semi also supports the use of dark mode in a partial area of the page.

Semi will automatically mount the global color palette on the root element (:root). We have built in some commonly used CSS Tokens. For detailed Token details, please refer to Design Variables We recommend that you configure color and background-color on the body, your business components can automatically inherit the default background color and text color from the body, and adaptive light/dark color switching

// css
body {
    color: var(--semi-color-text-0);
    background-color: var(--semi-color-bg-0);
}

How to switch

To use Dark Mode, you could simply add [theme-mode='dark'] to body in any way you prefer. The attribute works on any ancestor element. The variables are declared on :root and declared again on the element carrying theme-mode='dark', so read them on body or a descendant to get the dark values. Here is a quick idea:

const body = document.body;
if (body.hasAttribute('theme-mode')) {
    body.removeAttribute('theme-mode');
} else {
    body.setAttribute('theme-mode', 'dark');
}

For instance:

Code
import { Button } from '@fibrous/semi-ui-solid';

export default function DarkModeDemo() {
    const switchMode = () => {
        const body = document.body;
        if (body.hasAttribute('theme-mode')) {
            body.removeAttribute('theme-mode');
        } else {
            body.setAttribute('theme-mode', 'dark');
        }
    };

    return <Button onClick={switchMode}>Switch Mode</Button>;
}

Customize the colors of both modes

Override the --semi-* color variables in your own stylesheet: light values on :root, dark values on [theme-mode='dark']. Semi's styles sit in @layer semi, so your unlayered rules always win without !important:

:root {
    --semi-color-primary: var(--semi-violet-5);
}

[theme-mode='dark'] {
    --semi-color-primary: var(--semi-violet-4);
}

With partial light/dark mode, the .semi-always-light and .semi-always-dark elements declare the color variables again; to make an override reach those areas too, add the two classes to the selectors above.

Keep Consistency with System Theme

If you want the mode of the site to change with the system setting, you may find this property Prefers-color-scheme helpful. To change system setting in macOS, go to System Preferences -> General -> Appearance

You could add a listener for this property using js. Here is another example:

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');
        }
    }
}

matchMode(mql);
mql.addEventListener('change', matchMode);

Block Dark/Light Mode

Semi 2.0 natively supports block dark/bright color mode, and you can add .semi-always-dark or .semi-always-light to areas that require block dark or bright colors as needed.

Note: pop-up layers render in body, outside the element carrying .semi-always-dark or .semi-always-light. When the pop-up layer of Tooltip, Popover, Dropdown, or the dropdown of Select and similar components opens, it takes the class of the innermost .semi-always-dark or .semi-always-light element around its trigger, so it uses the same mode as the area of the trigger. Modal, SideSheet, Toast and Notification do not follow a trigger; they render in body by default and use the page theme.




Finished
This is a description.
2
In Progress
This is a description.
3
Waiting
This is a description.

Finished
This is a description
In Process
This is a description
3
Waiting
This is a description
XZ5
YB5
LX5
YZ
HW
XM

grey tag
blue tag
ghost tag
solid tag
red tag
green tag
orange tag
teal tag
violet tag
white tag

I am Popover
I am Tooltip

  • 审核中
    2019-07-14 10:35
  • 发布成功
    2019-06-13 16:17
  • 审核失败
    2019-05-14 18:34
Copyright © 2019 ByteDance. All Rights Reserved. 平台客服反馈建议
Code
import { createSignal } from 'solid-js';
import { Dynamic } from 'solid-js/web';
import { IconBell, IconBytedanceLogo, IconCamera, IconEdit, IconHelpCircle, IconHistogram, IconHome, IconList, IconLive, IconSemiLogo, IconSetting } from '@fibrous/semi-icons-solid';
import { Avatar, Badge, Breadcrumb, Button, Layout, Nav, Pagination, Popover, Rating, Row, Steps, Tag, Timeline, Tooltip } from '@fibrous/semi-ui-solid';

const rowStyle = { margin: '16px 10px' };
const badgeStyle = {
    width: '42px',
    height: '42px',
    'border-radius': '4px',
    display: 'inline-block',
};
const tagStyle = { 'margin-right': '8px', 'margin-bottom': '8px' };
const siderIcons: Record<string, typeof IconHome> = { Home: IconHome, Histogram: IconHistogram, Live: IconLive, Setting: IconSetting };
const optionIcons: Record<string, typeof IconHome> = { user: IconEdit, union: IconCamera, 'approve-management': IconList };

export default function DarkModeDemo() {
    const [mode, setMode] = createSignal('semi-always-dark');

    const switchMode = () => {
        setMode(mode() === 'semi-always-dark' ? 'semi-always-light' : 'semi-always-dark');
    };

    return (
        <>
            <Button onClick={switchMode} style={{ 'margin-bottom': '4px' }}>
                Switch Content Mode
            </Button>
            <Layout style={{ border: '1px solid var(--semi-color-border)' }}>
                <Layout.Header style={{ 'background-color': 'var(--semi-color-bg-1)' }}>
                    <div>
                        <Nav aria-label="顶部导航" mode="horizontal" defaultSelectedKeys={['Home']}>
                            <Nav.Header>
                                <IconSemiLogo style={{ width: '96px', height: '36px', 'font-size': '36px' }} />
                            </Nav.Header>
                            <span style={{ color: 'var(--semi-color-text-2)' }}>
                                <span style={{ 'margin-right': '24px', color: 'var(--semi-color-text-0)', 'font-weight': '600' }}>模版推荐</span>
                                <span style={{ 'margin-right': '24px' }}>所有模版</span>
                                <span>我的模版</span>
                            </span>
                            <Nav.Footer>
                                <Button theme="borderless" aria-label="通知" icon={<IconBell size="large" />} style={{ color: 'var(--semi-color-text-2)', 'margin-right': '12px' }} />
                                <Button theme="borderless" aria-label="帮助" icon={<IconHelpCircle size="large" />} style={{ color: 'var(--semi-color-text-2)', 'margin-right': '12px' }} />
                                <Avatar color="orange" size="small">
                                    YJ
                                </Avatar>
                            </Nav.Footer>
                        </Nav>
                    </div>
                </Layout.Header>
                <Layout>
                    <Layout.Sider style={{ 'background-color': 'var(--semi-color-bg-1)' }}>
                        <Nav
                            aria-label="侧边导航"
                            style={{ 'max-width': '220px', height: '100%' }}
                            defaultSelectedKeys={['Home']}
                            items={[
                                { itemKey: 'Home', text: '首页' },
                                { itemKey: 'Histogram', text: '基础数据' },
                                { itemKey: 'Live', text: '测试功能' },
                                { itemKey: 'Setting', text: '设置' },
                            ]}
                            renderItemIcon={({ item }) => <Dynamic component={siderIcons[String(item.itemKey)]} size="large" />}
                            footer={{
                                collapseButton: true,
                            }}
                        />
                    </Layout.Sider>
                    <Layout.Content class={mode()} style={{ padding: '24px', 'background-color': 'var(--semi-color-bg-1)' }}>
                        <Breadcrumb style={{ 'margin-bottom': '24px' }} routes={['首页', '当这个页面标题很长时需要省略', '上一页', '详情页']} />
                        <div style={{ 'border-radius': '10px', border: '1px solid var(--semi-color-border)', height: '700px', padding: '32px' }}>
                            <Row style={rowStyle}>
                                <Nav
                                    aria-label="示例导航"
                                    mode="horizontal"
                                    items={[
                                        { itemKey: 'user', text: 'Option1' },
                                        { itemKey: 'union', text: 'Option2' },
                                        {
                                            itemKey: 'approve-management',
                                            text: 'Group3',
                                            items: ['3-1', '3-2'],
                                        },
                                    ]}
                                    renderItemIcon={({ item }) => <Dynamic component={optionIcons[String(item.itemKey)]} />}
                                />
                                <br />
                                <br />
                                <Pagination total={80} showSizeChanger />
                                <br />
                                <Steps current={1}>
                                    <Steps.Step title="Finished" description="This is a description." />
                                    <Steps.Step title="In Progress" description="This is a description." />
                                    <Steps.Step title="Waiting" description="This is a description." />
                                </Steps>
                                <br />
                                <Steps current={1} status="error">
                                    <Steps.Step title="Finished" description="This is a description" />
                                    <Steps.Step title="In Process" description="This is a description" />
                                    <Steps.Step title="Waiting" description="This is a description" />
                                </Steps>
                            </Row>
                            <Row style={rowStyle}>
                                <div style={{ display: 'flex' }}>
                                    <div style={{ padding: '8px' }}>
                                        <Badge count={5} theme="solid">
                                            <Avatar color="blue" shape="square" style={badgeStyle}>
                                                XZ
                                            </Avatar>
                                        </Badge>
                                    </div>
                                    <div style={{ padding: '8px' }}>
                                        <Badge count={5} theme="light">
                                            <Avatar color="cyan" shape="square" style={badgeStyle}>
                                                YB
                                            </Avatar>
                                        </Badge>
                                    </div>
                                    <div style={{ padding: '8px' }}>
                                        <Badge count={5} theme="inverted">
                                            <Avatar color="indigo" shape="square" style={badgeStyle}>
                                                LX
                                            </Avatar>
                                        </Badge>
                                    </div>
                                    <div style={{ padding: '8px' }}>
                                        <Badge dot theme="solid">
                                            <Avatar color="light-blue" shape="square" style={badgeStyle}>
                                                YZ
                                            </Avatar>
                                        </Badge>
                                    </div>
                                    <div style={{ padding: '8px' }}>
                                        <Badge dot theme="light">
                                            <Avatar color="teal" shape="square" style={badgeStyle}>
                                                HW
                                            </Avatar>
                                        </Badge>
                                    </div>
                                    <div style={{ padding: '8px', 'border-radius': '4px', 'background-color': 'var(--semi-color-fill-0)' }}>
                                        <Badge dot theme="inverted">
                                            <Avatar color="green" shape="square" style={badgeStyle}>
                                                XM
                                            </Avatar>
                                        </Badge>
                                    </div>
                                </div>
                                <br />
                                <div>
                                    <Tag color="grey" style={tagStyle}>
                                        grey tag
                                    </Tag>
                                    <Tag color="blue" style={tagStyle}>
                                        blue tag
                                    </Tag>
                                    <Tag color="blue" type="ghost" style={tagStyle}>
                                        ghost tag
                                    </Tag>
                                    <Tag color="blue" type="solid" style={tagStyle}>
                                        solid tag
                                    </Tag>
                                    <Tag color="red" style={tagStyle}>
                                        red tag
                                    </Tag>
                                    <Tag color="green" style={tagStyle}>
                                        green tag
                                    </Tag>
                                    <Tag color="orange" style={tagStyle}>
                                        orange tag
                                    </Tag>
                                    <Tag color="teal" style={tagStyle}>
                                        teal tag
                                    </Tag>
                                    <Tag color="violet" style={tagStyle}>
                                        violet tag
                                    </Tag>
                                    <Tag color="white" style={tagStyle}>
                                        white tag
                                    </Tag>
                                </div>
                                <br />
                                <div style={{ display: 'flex', 'align-items': 'center' }}>
                                    <Popover content="hi semi-design" style={{ padding: '8px' }}>
                                        <Tag style={{ 'margin-right': '8px' }}>I am Popover</Tag>
                                    </Popover>
                                    <Tooltip content="hi semi-design">
                                        <Tag style={{ 'margin-right': '8px' }}>I am Tooltip</Tag>
                                    </Tooltip>
                                    <Rating defaultValue={3} size="small" style={{ 'margin-right': '8px' }} />
                                </div>
                                <br />
                                <Timeline>
                                    <Timeline.Item time="2019-07-14 10:35" type="ongoing">
                                        审核中
                                    </Timeline.Item>
                                    <Timeline.Item time="2019-06-13 16:17" type="success">
                                        发布成功
                                    </Timeline.Item>
                                    <Timeline.Item time="2019-05-14 18:34" type="error">
                                        审核失败
                                    </Timeline.Item>
                                </Timeline>
                            </Row>
                        </div>
                    </Layout.Content>
                </Layout>
                <Layout.Footer
                    style={{
                        display: 'flex',
                        'justify-content': 'space-between',
                        padding: '20px',
                        color: 'var(--semi-color-text-2)',
                        'background-color': 'var(--semi-grey-0)',
                    }}
                >
                    <span style={{ display: 'flex', 'align-items': 'center' }}>
                        <IconBytedanceLogo size="large" style={{ 'margin-right': '8px' }} />
                        <span>Copyright © 2019 ByteDance. All Rights Reserved. </span>
                    </span>
                    <span>
                        <span style={{ 'margin-right': '24px' }}>平台客服</span>
                        <span>反馈建议</span>
                    </span>
                </Layout.Footer>
            </Layout>
        </>
    );
}