SxThemeScope (主题作用域)

  • Implemented

在页面或容器级别覆盖主题颜色,利用 CSS 变量继承实现局部主题切换。子元素自动使用覆盖后的颜色,离开作用域后自动恢复全局主题。

使用场景

  • 某个页面需要独立的品牌色(如营销页、活动页)
  • 页面内局部区域需要不同主题(如深色侧边栏、浅色内容区)
  • 多个页面共享一套自定义主题(通过 Layout 包裹)
  • 嵌套使用:外层紫色、内层粉色等渐进式主题覆盖

工作原理

SxThemeScope 渲染一个 <div>,在其 style 属性中注入覆盖后的 CSS 变量。由于 CSS 变量天然支持继承,该 <div> 内的所有后代组件都会使用新值,不影响外部。

当组件被销毁(如导航离开页面),<div> 从 DOM 移除,覆盖消失,全局主题自动恢复。

基本用法

最简单的用法:覆盖主色

<SxThemeScope PrimarySeedHex="#FF6B35">
    <SxButton Appearance="ButtonAppearance.Accent">橙色按钮</SxButton>
</SxThemeScope>

覆盖主色 + 背景色

<SxThemeScope PrimarySeedHex="#6366F1" BackgroundSeedHex="#EEF2FF"
              Style="padding: 1.5rem; border-radius: var(--sx-borderRadiusLarge)">
    <SxTypography Variant="TypographyVariant.BodyStrong">浅紫色区域</SxTypography>
    <SxTypography>文字颜色自动适配背景。</SxTypography>
    <SxButton Appearance="ButtonAppearance.Accent">操作</SxButton>
</SxThemeScope>

设置 BackgroundSeedHex 后,组件自动添加 sx-theme-scope--has-bg 类,渲染为 display: block 并应用背景色和文字色。

页面级包裹

@page "/my-branded-page"

<SxThemeScope PrimarySeedHex="#FF6B35" BackgroundSeedHex="#FFF8F0">
    <h1>这个页面有自己的主题</h1>
    <SxButton Appearance="ButtonAppearance.Accent">橙色按钮</SxButton>
</SxThemeScope>

导航离开页面 → div 被移除 → 覆盖消失 → 自动恢复全局主题。

Layout 级共享(多个页面共享一套主题)

@* Layouts/BrandedLayout.razor *@
@inherits LayoutComponentBase

<SxThemeScope PrimarySeedHex="#10B981">
    @Body
</SxThemeScope>

嵌套作用域

<SxThemeScope PrimarySeedHex="#8B5CF6">
    <SxButton Appearance="ButtonAppearance.Accent">紫色按钮</SxButton>

    <SxThemeScope PrimarySeedHex="#EC4899">
        <SxButton Appearance="ButtonAppearance.Accent">粉色按钮</SxButton>
    </SxThemeScope>
</SxThemeScope>

内层作用域的 CSS 变量会覆盖外层,实现渐进式主题叠加。

使用 Overrides 对象

@code {
    private ThemeScopeOverrides _overrides = new()
    {
        PrimarySeedHex = "#E11D48",
        BackgroundSeedHex = "#FFF1F2",
        ExtraVariables = new Dictionary<string, string>
        {
            ["--sx-borderRadiusMedium"] = "1rem"
        }
    };
}

<SxThemeScope Overrides="_overrides">
    <SxCard>自定义主题卡片</SxCard>
</SxThemeScope>

约束说明

  • 弹窗/Popover 不继承覆盖:Blazor portal 机制会将弹窗内容渲染到 DOM 其他位置(如 <body> 直接子元素),不在 SxThemeScope 子树内,因此不会继承覆盖的 CSS 变量。这是 CSS 变量作用域的天然限制。
  • 无覆盖时为透明容器:当不设置 BackgroundSeedHex 时,组件使用 display: contents,不影响布局。
  • Overrides 优先于快捷参数:如果同时设置 OverridesPrimarySeedHex/BackgroundSeedHexOverrides 优先。

生成的 CSS 变量

PrimarySeedHex 生成的变量

变量名 说明
--sx-primary-seed 种子色原值
--sx-primary-50 ~ --sx-primary-900 10 级色阶调色板
--sx-primary-hover 悬停色(种子色调暗 10%)
--sx-primary-container 容器色(种子色 15% 透明度)
--sx-color-on-brand 品牌色上的文字色(自动黑/白)
--sx-colorBrandBackground1 品牌背景(= 种子色)
--sx-colorBrandForeground1 品牌前景(= 种子色)
--color-brand-primary 兼容别名
--color-brand-N 兼容调色板别名
--ds-button-primary-bg Legacy 别名

BackgroundSeedHex 生成的变量

变量名 说明
--sx-colorNeutralBackground1/2/3 中性背景色
--sx-colorNeutralBackgroundDisabled 禁用背景色
--sx-colorNeutralForeground1/2/3 中性前景色(WCAG 对比度 ≥ 4.5)
--sx-colorNeutralStroke1/2 描边色
--color-bg-page, --color-bg-surface 兼容别名
--color-text-primary/secondary 兼容别名
--ds-surface-bg, --ds-text-primary Legacy 别名

API

Parameters

状态 参数名 类型 默认值 描述
Implemented ChildContent RenderFragment? null 子内容。
Implemented Overrides ThemeScopeOverrides? null 完整覆盖对象,优先于快捷参数。
Implemented PrimarySeedHex string? null 快捷参数:主色种子 hex(如 "#FF6B35")。
Implemented BackgroundSeedHex string? null 快捷参数:背景色种子 hex(如 "#FFF8F0")。
Implemented Id (继承) string? null 组件的物理 Id。
Implemented Class (继承) string? null 自定义 CSS 类名。
Implemented Style (继承) string? null 自定义样式(与覆盖变量合并)。

ThemeScopeOverrides

属性 类型 描述
PrimarySeedHex string? 主色种子,生成完整品牌调色板。
BackgroundSeedHex string? 背景色种子,生成中性色板(背景/前景/描边)。
ExtraVariables Dictionary<string, string>? 额外自定义 CSS 变量。

CSS Classes

类名 说明
sx-theme-scope 始终存在的基础类。无背景时 display: contents
sx-theme-scope--has-bg 设置了 BackgroundSeedHex 时添加。display: block,应用背景色和文字色。

与 SxThemeProvider 的关系

SxThemeProvider SxThemeScope
作用范围 全局(整个应用) 局部(包裹的子树)
实现方式 JS 设置 :root CSS 变量 纯 CSS inline style
需要 JS
数量限制 整个应用只放一次 可以多处使用、嵌套
持久化 自动保存到偏好设置 无持久化(随组件生命周期)

参考设计 (References)