Blazor可复用组件:如何将背景色字符串转为HSL格式
Blazor组件中实现字符串背景色转HSL并自动计算文本配色
方法一:C#后端解析颜色(兼容所有Blazor宿主)
由于System.Drawing在Blazor WebAssembly环境中无法使用,我们可以手动实现颜色解析逻辑,将常见格式的颜色字符串(十六进制、RGB/RGBA)转换为HSL格式。
首先定义HSL数据结构:
public struct HslColor { public double Hue { get; set; } // 取值范围0-360 public double Saturation { get; set; } // 取值范围0-100(百分比) public double Lightness { get; set; } // 取值范围0-100(百分比) public double Alpha { get; set; } // 取值范围0-1 }
实现颜色解析工具类:
public static class ColorParser { public static HslColor ParseToHsl(string colorString) { // 处理空值或无效输入, fallback到默认色 if (string.IsNullOrWhiteSpace(colorString)) return ParseHexToHsl("#DEF4F58C"); // 处理十六进制格式(#RRGGBB 或 #RRGGBBAA) if (colorString.StartsWith("#")) return ParseHexToHsl(colorString); // 处理RGB/RGBA格式 if (colorString.StartsWith("rgb(") || colorString.StartsWith("rgba(")) return ParseRgbToHsl(colorString); // 格式不支持时返回默认值 return ParseHexToHsl("#DEF4F58C"); } private static HslColor ParseHexToHsl(string hex) { // 处理缩写格式(如#RGB、#RGBA) hex = hex.TrimStart('#'); if (hex.Length == 3) hex = $"{hex[0]}{hex[0]}{hex[1]}{hex[1]}{hex[2]}{hex[2]}FF"; else if (hex.Length == 4) hex = $"{hex[0]}{hex[0]}{hex[1]}{hex[1]}{hex[2]}{hex[2]}{hex[3]}{hex[3]}"; else if (hex.Length == 6) hex += "FF"; // 解析RGBA值为0-1的小数 var r = Convert.ToInt32(hex.Substring(0, 2), 16) / 255.0; var g = Convert.ToInt32(hex.Substring(2, 2), 16) / 255.0; var b = Convert.ToInt32(hex.Substring(4, 2), 16) / 255.0; var a = Convert.ToInt32(hex.Substring(6, 2), 16) / 255.0; return RgbToHsl(r, g, b, a); } private static HslColor ParseRgbToHsl(string rgb) { // 提取RGB/RGBA中的数字部分 var parts = rgb.Replace("rgb(", "") .Replace("rgba(", "") .Replace(")", "") .Split(',') .Select(p => double.TryParse(p.Trim(), out var val) ? val : 0) .ToArray(); var r = parts[0] / 255.0; var g = parts[1] / 255.0; var b = parts[2] / 255.0; var a = parts.Length >=4 ? parts[3] : 1; return RgbToHsl(r, g, b, a); } private static HslColor RgbToHsl(double r, double g, double b, double a) { double max = Math.Max(r, Math.Max(g, b)); double min = Math.Min(r, Math.Min(g, b)); double h, s, l = (max + min) / 2; if (max == min) { h = s = 0; // 灰度色 } else { double d = max - min; s = l > 0.5 ? d / (2 - max - min) : d / (max + min); if (max == r) h = (g - b) / d + (g < b ? 6 : 0); else if (max == g) h = (b - r) / d + 2; else h = (r - g) / d + 4; h *= 60; } return new HslColor { Hue = Math.Round(h), Saturation = Math.Round(s * 100), Lightness = Math.Round(l * 100), Alpha = a }; } }
在Blazor组件中使用:
@code { /// <summary> /// Define the colour of the card. It can accept any string value. The default is #DEF4F58C Hexadecimal. /// </summary> [Parameter] public string BackgroundColour { get; set; } = "#DEF4F58C"; private HslColor _bgHsl; protected override void OnInitialized() { _bgHsl = ColorParser.ParseToHsl(BackgroundColour); } // 根据背景亮度自动计算文本颜色 private string TextColour => _bgHsl.Lightness > 50 ? "#000000" : "#FFFFFF"; }
将HSL值通过CSS变量传递给组件样式:
<div style="background-color: @BackgroundColour; color: @TextColour; --bg-h: @_bgHsl.Hue; --bg-s: @_bgHsl.Saturation%; --bg-l: @_bgHsl.Lightness%"> <!-- 组件内容 --> </div>
方法二:前端JS互操作(利用浏览器的颜色解析能力)
如果不想手动处理复杂颜色格式(比如命名色red、原生HSL格式),可以借助浏览器的getComputedStyle API自动解析。
添加JS方法(放在wwwroot/js/interop.js):
window.getColorAsHsl = async (elementId) => { const element = document.getElementById(elementId); if (!element) return null; const computedStyle = getComputedStyle(element); const bgColor = computedStyle.backgroundColor; // 利用浏览器将任意颜色转换为HSL格式 const tempDiv = document.createElement('div'); tempDiv.style.color = bgColor; document.body.appendChild(tempDiv); const hslColor = getComputedStyle(tempDiv).color; document.body.removeChild(tempDiv); // 提取HSL数值 const matches = hslColor.match(/hsl\((\d+),\s*(\d+)%,\s*(\d+)%\)/); if (!matches) return null; return { hue: parseInt(matches[1]), saturation: parseInt(matches[2]), lightness: parseInt(matches[3]), alpha: bgColor.includes('rgba') ? parseFloat(bgColor.split(',')[3].replace(')', '')) : 1 }; };
在Blazor组件中调用:
@inject IJSRuntime JSRuntime <!-- 用于解析颜色的隐藏元素 --> <div id="bg-color-target" style="display: none; background-color: @BackgroundColour"></div> <div style="background-color: @BackgroundColour; color: @TextColour; --bg-h: @_bgHsl.Hue; --bg-s: @_bgHsl.Saturation%; --bg-l: @_bgHsl.Lightness%"> <!-- 组件内容 --> </div> @code { [Parameter] public string BackgroundColour { get; set; } = "#DEF4F58C"; private HslColor _bgHsl; private string TextColour => _bgHsl.Lightness > 50 ? "#000000" : "#FFFFFF"; protected override async Task OnAfterRenderAsync(bool firstRender) { if (firstRender) { var hslData = await JSRuntime.InvokeAsync<HslColor>("getColorAsHsl", "bg-color-target"); if (hslData != null) { _bgHsl = hslData; StateHasChanged(); } } } public struct HslColor { public int Hue { get; set; } public int Saturation { get; set; } public int Lightness { get; set; } public double Alpha { get; set; } } }
使用CSS calc实现动态配色
得到HSL变量后,可通过CSS calc实现更灵活的配色逻辑:
.card-content { /* 文本颜色随背景亮度反向调整 */ color: hsl(var(--bg-h), var(--bg-s), calc(var(--bg-l) > 50 ? 10% : 90%)); /* 边框颜色比背景深/浅10% */ border-color: hsl(var(--bg-h), var(--bg-s), calc(var(--bg-l) - 10%)); }
内容的提问来源于stack exchange,提问作者Ben Pugh
相关产品推荐
相关产品推荐

