.NET MAUI Blazor如何为明暗主题设置自动适配的颜色?
.NET MAUI Blazor 适配深色/浅色主题的实现方案
以下是几种实用的主题适配方法,可实现自动跟随系统或手动切换主题的样式效果:
方法一:利用MAUI主题资源+Blazor CSS变量(跟随系统主题)
这种方式让MAUI管理主题资源,Blazor通过CSS变量复用这些资源,自动跟随系统主题切换。
- 定义主题颜色资源
在项目的Resources/Styles/Colors.xaml中分别定义浅色、深色模式的颜色:
<Color x:Key="PrimaryLight">#2196F3</Color> <Color x:Key="PrimaryDark">#1976D2</Color> <Color x:Key="BackgroundLight">#FFFFFF</Color> <Color x:Key="BackgroundDark">#121212</Color> <Color x:Key="TextLight">#333333</Color> <Color x:Key="TextDark">#EEEEEE</Color>
- 映射资源到CSS变量
在App.xaml中通过CssProperty将MAUI资源映射为Blazor可识别的CSS变量:
<Application.Resources> <ResourceDictionary> <!-- 绑定主题资源 --> <StaticResource x:Key="Primary" ResourceKey="{AppThemeBinding Light=PrimaryLight, Dark=PrimaryDark}" /> <StaticResource x:Key="Background" ResourceKey="{AppThemeBinding Light=BackgroundLight, Dark=BackgroundDark}" /> <StaticResource x:Key="TextColor" ResourceKey="{AppThemeBinding Light=TextLight, Dark=TextDark}" /> <!-- 映射到CSS变量 --> <CssProperty x:Key="--primary-color" Value="{StaticResource Primary}" /> <CssProperty x:Key="--bg-color" Value="{StaticResource Background}" /> <CssProperty x:Key="--text-color" Value="{StaticResource TextColor}" /> </ResourceDictionary> </Application.Resources>
- Blazor中使用CSS变量
在wwwroot/css/app.css里使用这些变量编写样式:
body { background-color: var(--bg-color); color: var(--text-color); margin: 0; padding: 1rem; } .btn-primary { background-color: var(--primary-color); color: white; border: none; padding: 0.5rem 1rem; border-radius: 4px; cursor: pointer; }
系统切换主题时,MAUI会自动更新资源值,Blazor的样式会同步变化。
方法二:Blazor CSS媒体查询(纯前端方式)
直接通过CSS的媒体查询监听系统主题偏好,无需依赖MAUI资源配置:
在 wwwroot/css/app.css 中编写如下样式:
/* 浅色模式默认样式 */ body { background-color: #FFFFFF; color: #333333; } .btn-primary { background-color: #2196F3; color: white; } /* 深色模式适配样式 */ @media (prefers-color-scheme: dark) { body { background-color: #121212; color: #EEEEEE; } .btn-primary { background-color: #1976D2; } }
浏览器会自动根据系统的主题偏好应用对应的样式规则。
方法三:手动切换主题+持久化(自定义主题切换)
如果需要让用户手动切换主题并记住选择,可通过Blazor服务+本地存储实现:
- 创建主题管理服务
public class ThemeService { public string CurrentTheme { get; set; } = "light"; public event Action OnThemeChanged; public void ToggleTheme() { CurrentTheme = CurrentTheme == "light" ? "dark" : "light"; OnThemeChanged?.Invoke(); } }
在 Program.cs 中注册服务:
builder.Services.AddScoped<ThemeService>();
- 组件中实现主题切换逻辑
创建一个主题切换组件(比如ThemeToggle.razor):
@inject ThemeService ThemeService @implements IDisposable @inject IJSRuntime JSRuntime <button @onclick="ToggleTheme" class="btn-primary">切换主题</button> @code { protected override async Task OnInitializedAsync() { // 从本地存储读取保存的主题 var savedTheme = await JSRuntime.InvokeAsync<string>("localStorage.getItem", "theme"); if (!string.IsNullOrEmpty(savedTheme)) { ThemeService.CurrentTheme = savedTheme; await UpdateThemeClass(); } ThemeService.OnThemeChanged += UpdateThemeClass; } private async Task ToggleTheme() { ThemeService.ToggleTheme(); // 保存主题到本地存储 await JSRuntime.InvokeVoidAsync("localStorage.setItem", "theme", ThemeService.CurrentTheme); } private async Task UpdateThemeClass() { var body = await JSRuntime.InvokeAsync<IJSObjectReference>("document.getElementsByTagName", "body"); await body.InvokeVoidAsync("classList.remove", "light", "dark"); await body.InvokeVoidAsync("classList.add", ThemeService.CurrentTheme); } public void Dispose() { ThemeService.OnThemeChanged -= UpdateThemeClass; } }
- 编写对应主题类的CSS
在wwwroot/css/app.css中添加类选择器样式:
body.light { background-color: #FFFFFF; color: #333333; } body.dark { background-color: #121212; color: #EEEEEE; } body.light .btn-primary { background-color: #2196F3; } body.dark .btn-primary { background-color: #1976D2; }
内容的提问来源于stack exchange,提问作者Nidhi Singla
相关产品推荐
相关产品推荐

