Info Badge 用来在应用内非打断地提示「有新内容 / 有未读数 / 需要留意」,典型落点是 NavigationView 的菜单项、按钮的一角、列表项的尾部(WinUI 官方描述:badging is a non-intrusive and intuitive way to display notifications or bring focus to an area within an app)。
样式与几何对齐 WinUI 3 / Windows App SDK 的 InfoBadge(microsoft-ui-xaml,InfoBadge 目录在 winui3/release/2.0.1——最新 WinUI3 Gallery 发行版 v2.9.3 所用的 WindowsAppSDK 版本——与 winui3/release/2.5.1 之间逐字节一致):
InfoBadgeMinWidth / InfoBadgeMinHeight)、最大高 16(InfoBadgeMaxHeight)、宽度不限、圆角 = 实际高的一半(InfoBadge.cpp#OnSizeChanged)。Value >= 0 显示数字(11px,InfoBadgeValueFontSize);否则有 IconSource 显示图标;否则是一个 4×4 的圆点。InfoBadge.cpp#MeasureOverride 在「宽 < 高」时返回正方形,所以单个数字的徽章是正圆而不是窄胶囊。Viewbox 撑满「最大高 − 内外边距」= 8px(模板里的 InfoBadgeIconWidth / InfoBadgeIconHeight 两个资源没有被模板引用,是死资源)。value 与 icon 两个 Prop 的组合决定形态,推导顺序逐字对齐 InfoBadge.cpp#OnDisplayKindPropertiesChanged(Value 优先于 Icon):
| 条件 | 形态 | 对应 WinUI |
|---|---|---|
value >= 0 | value | Value 视觉状态 |
有 icon(或 #icon 插槽) | icon | Icon / FontIcon 视觉状态 |
| 都不满足 | dot | Dot 视觉状态(空状态) |
severity 对应 InfoBadge_themeresources.xaml 里的 Style 键:每一档都有 Dot / Value / Icon 三个变体,底色完全相同,差别只在「是否预置 IconSource」与「图标态是否额外加 Padding=0,4,0,2」(后者与 IconInfoBadgeIconMargin 在图标态下几何等价,见「实现要点」)。
severity | WinUI Style 前缀 | 底色资源 |
|---|---|---|
accent(缺省) | DefaultInfoBadgeStyle | AccentFillColorDefaultBrush |
attention | Attention*InfoBadgeStyle | SystemFillColorAttentionBrush |
informational | Informational*… | SystemFillColorSolidNeutralBrush |
success | Success*… | SystemFillColorSuccessBrush |
caution | Caution*… | SystemFillColorCautionBrush |
critical | Critical*… | SystemFillColorCriticalBrush |
Attention · Dot / Value / Icon
徽章最常见的落点是导航项与控件一角。徽章本身是纯装饰元素,可访问名应当挂在承载它的控件上(Gallery 就是这么写的:AutomationProperties.Name="Inbox, 5 notifications")。
已刷新 0 次
value 是响应式的:>= 0 显示数字,< 0 回到圆点形态(WinUI 的 Value 缺省就是 -1)。
| 属性(Props) | 类型 | 默认 | 说明 |
|---|---|---|---|
value | number | -1 | 徽章数值(Int32);>= 0 显示数字,< 0 回落到图标 / 圆点;对齐 WinUI Value |
severity | 'accent' | 'attention' | 'informational' | 'success' | 'caution' | 'critical' | 'accent' | 背景预设;对齐六套 *InfoBadgeStyle |
icon | boolean | Component | null | — | 图标;true 取 severity 的内建字形,也可直接传图标组件;对齐 WinUI IconSource |
borderRadius | string | — | 圆角;不传时对齐 OnSizeChanged 的 ActualHeight / 2(全圆角) |
label | string | — | 可访问名;不传则整个徽章 aria-hidden(对齐「InfoBadge 没有 AutomationPeer」) |
| 插槽(Slots) | 说明 |
|---|---|
icon | 对应 WinUI IconSource;提供后进入 Icon 形态,并覆盖 icon Prop 与内建字形 |
无障碍:WinUI 的 InfoBadge 没有
AutomationPeer(Control.OnCreateAutomationPeer未重写,UIA 树里不出现),Gallery 因此把可访问名挂在父级NavigationViewItem上。本组件缺省渲染aria-hidden="true"、不抢 Tab 序、不拦截指针;只有显式传入label时才渲染role="img"+aria-label(独立使用场景)。组件不硬编码任何自然语言。实现要点
- 形态是实时推导的,不是一个
variant枚举:InfoBadge.cpp#OnDisplayKindPropertiesChanged里Value >= 0→Value态,否则IconSource != null→FontIcon/Icon态,否则Dot态。本组件的displayKindcomputed 与之逐字对应(含「Value 优先于 Icon」),并通过data-display-kind暴露出来,便于样式与测试断言。- 两种图标形态在几何上等价:模板里 FontIcon 态用
InfoBadgePadding(被*IconInfoBadgeStyle覆盖为0,4,0,2)+IconInfoBadgeFontIconMargin(4,0,4,2),Icon 态用InfoBadgePadding(0)+IconInfoBadgeIconMargin(4,4,4,4)——两者都得到「上下 4 + 4、左右 4 + 4」与 8px 的Viewbox高度,所以本库统一用「8px 图标框 + 4px 外边距」一份规则表达,不再需要paddingProp。MeasureOverride的正方形规则用 CSS 表达:Value / Icon 两态的最终高都被InfoBadgeMaxHeight夹到 16,因此「宽 < 高则取正方形」等价于这两态各加一条min-inline-size: 16px;Dot 态的高就是InfoBadgeMinHeight(4,与MinWidth相等),不受影响。- 数值行高锁定为
lineHeightBase100(14px):14 +ValueInfoBadgeTextMargin的下外边距 2 = 16 =InfoBadgeMaxHeight,与 WinUI 里TextBlock的自然行高(≈14.67px)被MaxHeight夹到 16 的结果一致,且不随 Web 字体度量漂移;4,0,4,2这个上下不对称的外边距造成的「文字视觉中心比徽章中心高 1px」也一并保留。InfoBadgeIconWidth/InfoBadgeIconHeight不落地:这两个资源(12 / 8,Light 与 HC 主题下是 12 / 9)在InfoBadge.xaml的模板里没有被引用,图标实际尺寸由Viewbox撑满可用高决定 —— 死资源不写进代码,避免下次照着它去“还原”。- 五档底色与 InfoBar 共用一套映射:
SystemFillColor{Attention,Success,Caution,Critical}Brush与 InfoBar 的InfoBar*SeverityIconBackground是同一批资源,故沿用colorCompoundBrandBackground/colorStatusSuccessForeground3/colorPaletteYellowForeground1/colorStatusDangerForeground3;informational的SystemFillColorSolidNeutralBrush在 Fluent 2 Web 里没有同值项,按max(亮色 ΔE, 暗色 ΔE)最小取colorNeutralForeground4(CIE ΔE76,脚本temp/pw-infobadge.mjs会实测复核):
Severity WinUI 原值(Light / Dark) 本库 token ΔE(Light / Dark) accent 系统强调色 colorCompoundBrandBackground—(见下) attention 系统强调色( …ColorLight2)colorCompoundBrandBackground—(见下) informational #8A8A8A/#9D9D9DcolorNeutralForeground410.2 / 1.5 success #0F7B0F/#6CCB5FcolorStatusSuccessForeground30.4 / 30.8 caution #9D5D00/#FCE100colorPaletteYellowForeground126.5 / 23.0 critical #C42B1C/#FF99A4colorStatusDangerForeground37.3 / 15.2 前景 #FFFFFF/#000000colorNeutralForegroundInverted20.0 / 14.2
强调色不在仓库里(style-spec §2 的例外条款):AccentFillColorDefaultBrush/SystemFillColorAttentionBrush都由系统强调色在运行时注入,实机与截图的蓝可能是用户的自定义色,故两者都取 Fluent 默认强调色 token,accent与attention在 Web 上同色 —— 语义差异体现在内建字形上。success的暗色一档 ΔE 偏大(30.8),这是与 InfoBar 保持同一映射的代价;需要严格对齐实机时用下面的局部变量覆盖。
六档底色与前景都留了覆盖口子(同 InfoBar 口径):.my-badge { --fui-info-badge-bg: #dff6dd; /* 例如 SystemFillColorSuccess 原值 */ --fui-info-badge-fg: #ffffff; }- 五档内建字形都是「裸字形」,且是照图形挑的:把官方 Segoe Fluent Icons 字体按真实尺寸(16px 圆底 + 8px 字形框)渲染出来比对(脚本
temp/infobadge-visual/glyph-badge-compare.mjs)可以确认,*IconInfoBadgeStyle预置的五个字形都不带圆底——圆底由徽章本体提供。这一点很关键:InfoBar 用的是F136(实心圆)+F13F(i)两个字形叠加,而InformationalIconInfoBadgeStyle只给了F13F一个字形,不能照搬 InfoBar 的圆形图标。
Severity WinUI IconSourceSegoe 字形 本库图标 attentionFontIconSource Glyph=Asterisk(8 芒星号)text_asterisk_16_filledinformationalFontIconSource Glyph=裸 iinfo_16_regularsuccessSymbolIconSource Symbol=AcceptE8FB裸对勾checkmark_16_filledcautionSymbolIconSource Symbol=ImportantE171裸感叹号important_16_filledcriticalSymbolIconSource Symbol=CancelE711裸叉dismiss_16_filled
已知偏差:Fluent System Icons 没有裸字形i(已对 16px filled 全量 1,729 个图标做「窄高包围盒 + 恰好两个连通块 + 上块更小」的自动扫描,短名单为空,见temp/infobadge-visual/find-bare-i.mjs)。info_16_filled是「实心圆 + 镂空 i」,直接放上去会得到白圆盘 + 徽章色 i(前景 / 底色关系与 WinUI 相反,实测墨迹覆盖率 78% vs 本库 22%);info_16_regular是同一份i(子路径与 filled 的镂空 i 几何完全相同)外面多一圈 1 单位宽的白环,i仍是白色前景 —— 只多一处细环的偏差,故选 regular。需要完全一致时用#icon插槽换成自绘字形。
墨迹尺寸实测(temp/pw-infobadge.mjs第 3 节):WinUI 侧用官方 Segoe Fluent Icons 字体量出字形墨迹与线盒,按「Viewbox把线盒(= 1em)缩放到 8px 图标框」换算成 1x 尺寸(脚本temp/infobadge-visual/measure-segoe-ink.mjs);本库侧从 1:1 元素截图统计与底色有差异的像素外接框。
Severity 本库图标墨迹(1x) WinUI 1x 墨迹 Δ attention6×6 7.0×7.0 −1.0 success6×5 8.0×5.5 −2.0 / −0.5 caution2×6 3.0×8.0 −1.0 / −2.0 critical6×6 5.5×5.5 +0.5 informational8×8(细环 + i) 0.8×3.3(裸 i) 结构性偏差
前四档差 1–2px,来源是两套图标集的设计留白不同:Fluent System Icons 的 16px 字形墨迹约占外框 12/16,Segoe 的符号字形几乎填满 em 框;图标框的映射本身是对的(Fluent 的viewBox↔ Segoe 的 em 框,二者都由Viewbox缩放)。informational那一行是上面说的结构性偏差 —— WinUI 的F13F是一根 0.8px 宽的细i(1x 下几乎不可见),本库在官方图标集里找不到裸i,退而取「细环 +i」。- 参考图交叉验证(C 级证据,只比尺度无关的量):Gallery 截图里强调色徽章高度均为 16px、
Different InfoBadge Styles一行为 16×16(Icon)/ 19×16(Value「10」)/ 4×16(Dot)、NavigationView 里「5」那枚数值徽章是 16×16 正圆 —— 与InfoBadgeMaxHeight=16、MeasureOverride的正方形规则、InfoBadgeMinWidth/Height=4逐项吻合(见temp/pw-infobadge.mjs第 4 节与temp/visual-infobadge/下的截图)。唯一差异是 Value 胶囊比实机宽约 3px(宽高比 1.38 vs 1.19),来自 Web 字体度量(Segoe UI vs Segoe UI Variable)。- 已知缺口:高对比度主题未实现(WinUI HC 下底色
SystemControlHighlightAccentBrush、前景SystemControlHighlightAltChromeWhiteBrush);InfoBadgeIconWidth / Height两个死资源不落地。组件没有任何 Storyboard / VisualTransition,因此不涉及动效与prefers-reduced-motion。- 与 WinUI 的 API 差异:
Value < -1时 WinUI 抛hresult_out_of_bounds,本库按< 0处理(回落到 Dot),渲染期不抛异常;IconSource→iconProp /#icon插槽;TemplateSettings不对外暴露。