Blazor 生态里,Bootstrap 样式的组件库选择不多,BootstrapBlazor 是其中维护最积极、组件覆盖最广的一个。v10.7.0 的改动不算大,但 ThemeProvider 对 auto 值的处理方式做了一个值得注意的修正——如果你在项目中依赖主题自动切换逻辑,这个变更直接影响运行行为。
ThemeProvider:auto 不再被实际值"吞噬"
之前的版本里,ThemeProvider 的 auto 模式存在一个语义问题:当系统检测到用户偏好(比如操作系统暗色模式)后,auto 这个值会被替换成实际的 dark 或 light。这意味着一旦触发替换,你就丢失了"跟随系统"这个意图——用户后续切换系统主题,组件不会再响应。
v10.7.0 修正了这个行为:auto 值被保留,不再用实际值覆盖。组件内部在渲染时根据 auto 去实时读取系统偏好,而不是把 auto"凝固"成dark/light` 后就忘了初衷。
这个修正的影响面:
- 依赖
Theme属性做条件判断的代码,之前可能拿到dark,现在拿到auto,判断逻辑需要调整。 - 手动读取
ThemeProvider.Value做持久化的场景,存下来的值从dark变成了auto,反序列化后行为更正确。
OctIcons 依赖更新到 10.0.3
OctIcons 是 GitHub 开源的图标集,BootstrapBlazor 把它作为可选图标依赖集成。这次更新把依赖版本拉到 10.0.3,主要是一些图标新增和 SVG 路径修正。如果你的项目用了 OctIcon 组件,升级后图标渲染不会有破坏性变化,但可以用到新增图标。
实践:在项目中正确使用 ThemeProvider 的 auto 模式
下面是一个最小可运行的 Blazor 项目示例,展示 ThemeProvider 在 v10.7.0 下的正确用法。
先确认项目引用了正确版本:
<!-- BootstrapBlazor.csproj -->
<Project Sdk="Microsoft.NET.Sdk.Web">
<PropertyGroup>
<TargetFramework>net9.0</TargetFramework>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="BootstrapBlazor" Version="10.7.0" />
</ItemGroup>
</Project>
在 _Imports.razor 中引入组件命名空间:
@using BootstrapBlazor.Components
在 App.razor 或布局文件中放置 ThemeProvider,并设置默认值为 auto:
<!-- App.razor 或 MainLayout.razor -->
<ThemeProvider Value="@theme" OnValueChanged="@OnThemeChanged">
<div class="@GetThemeClass()">
@Body
</div>
</ThemeProvider>
@code {
// 初始值设为 auto,跟随操作系统偏好
private string theme = "auto";
// v10.7.0 中,OnValueChanged 回调的值是 "auto" 而非 "dark"/"light"
private void OnThemeChanged(string val)
{
theme = val;
// 如果需要持久化,直接存 "auto" 即可
// localStorage 保存逻辑可在此处添加
}
// 渲染时根据 auto 实际含义决定 CSS 类
private string GetThemeClass()
{
if (theme == "auto")
{
// 读取系统偏好:JS interop 或 CSS media query
// 简化示例:用 CSS 变量 + media query 处理
return "theme-auto";
}
return theme == "dark" ? "theme-dark" : "theme-light";
}
}
对应的 CSS 处理 auto 的实际渲染(放在 app.css 或布局样式里):
/* theme-auto 由浏览器 media query 决定实际样式 */
.theme-auto {
--bg: var(--light-bg);
--text: var(--light-text);
}
@media (prefers-color-scheme: dark) {
.theme-auto {
--bg: var(--dark-bg);
--text: var(--dark-text);
}
}
.theme-dark {
--bg: var(--dark-bg);
--text: var(--dark-text);
}
.theme-light {
--bg: var(--light-bg);
--text: var(--light-text);
}
关键点:不要把 auto 当作 dark 或 light 来判断。v10.7.0 之后,ThemeProvider 的值在 auto 模式下始终是 "auto" 字符串,实际视觉表现由 CSS media query 或 JS interop 在渲染层解决。
如果你之前有类似这样的代码:
<!-- ⚠ 旧版本下的判断,v10.7.0 后不再正确 -->
@if (theme == "dark")
{
<p>当前是暗色模式</p>
}
需要改为:
<!-- ✅ v10.7.0 正确判断 -->
@if (theme == "dark" || (theme == "auto" && isSystemDark))
{
<p>当前是暗色模式</p>
}
其中 isSystemDark 可以通过 JS interop 获取:
// themeHelper.js
export function isSystemDark() {
return window.matchMedia('(prefers-color-scheme: dark)').matches;
}
// 在 Razor 组件中调用
@inject IJSRuntime JS
private bool isSystemDark;
protected override async Task OnInitializedAsync()
{
var module = await JS.InvokeAsync<IJSObjectReference>("import", "./themeHelper.js");
isSystemDark = await module.InvokeAsync<bool>("isSystemDark");
}
升级注意事项
-
检查 Theme 值判断逻辑:所有硬编码判断
== "dark"或== "light"的地方,确认是否需要兼容auto值。这是本次升级最可能出问题的点。 -
持久化数据兼容:如果之前 localStorage 里存的是
dark/light,升级后新用户会存auto。读取时需要兼容两种格式——遇到auto就走跟随系统逻辑,遇到dark/light就走固定模式。 -
OctIcons 无破坏性变化:用了就升级,没用就不影响。新增图标可在 OctIcons 10.0.3 release notes 里查阅。
-
CSS 变量方案优先:处理
auto的实际渲染时,CSSprefers-color-schememedia query 比 JS interop 更可靠、更少延迟。尽量把主题切换的视觉表现层交给 CSS,C# 侧只管语义值。
BootstrapBlazor 的这次更新改动不大,但 ThemeProvider 的 auto 语义修正是那种"不改没事、改了要注意"的类型。升级前花十分钟扫一遍主题相关判断逻辑,基本就能平稳过渡。