news 2026/9/8 21:05:25

Bevy UI 的 em/rem 字号单位:Val::Em、Val::Rem 迁移与实战指南(0.19 → 0.20)

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
Bevy UI 的 em/rem 字号单位:Val::Em、Val::Rem 迁移与实战指南(0.19 → 0.20)

Bevy UI 的 em/rem 字号单位:Val::Em、Val::Rem 迁移与实战指南(0.19 → 0.20)

【免费下载链接】bevyA refreshingly simple>项目地址: https://gitcode.com/GitHub_Trending/be/bevy

Bevy UI 在 0.20 中引入了emrem两种相对字号单位,使Val的解析结果能够跟随字体大小缩放,这对"设计时定死像素、运行期调整字号"的可访问性与多设备适配场景非常有用。本文以官方迁移指南 val_em_and_rem.md 为主体,结合 release notes 与仓库源码,完整讲解新增的Val::Em/Val::Rem变体、受影响的resolve方法签名、EmSize组件的生命周期,以及GridTrackFontSize::eval等周边 API 的迁移方式。

为什么需要 em 和 rem

em表示"当前节点字号的倍数",rem表示"根字号(全局基准字号)的倍数"。两者的数据来源不同:

  • em:相对于设置该值的节点自身的字号,由节点实体上的EmSize组件提供;
  • rem:相对于全局的根字号,由既有的RemSize资源提供。

典型场景是:你希望 UI 在作者态下布局合理,但又能在运行期整体放大或缩小文字(例如无障碍功能,或在不同分辨率/设备上的适配)。若尺寸全部用px硬编码,改字号后布局会失衡;用em/rem表达,尺寸就能随字号一起伸缩。

官方给出的最小示例(bsn!语法):

bsn! { Node { width: em(10) } Text("Hello") TextFont { font_size: FontSize::Rem(1.5) } }

另外注意一个行为变化:默认字号从px(20)变为rem(1)。如果你从不修改RemSize,这只是无副作用的等价替换;但一旦你调整了RemSize,默认文字会随之缩放。

Val 新增变体与字符串解析

在 geometry.rs 中,Val枚举新增了两个变体(见 L58-L67):

/// Set this value as a multiple of the node's own font size. /// /// `1em` is the node's font size, so `Val::Em(2.0)` is twice that. /// Resolved from the node's [`EmSize`] component. Em(f32), /// Set this value as a multiple of the root font size. /// /// Unlike [`Val::Em`] this ignores the node's own font size, so it means the same /// length anywhere in the hierarchy. Resolved from the [`RemSize`] resource. Rem(f32),
  • Val::Em解析时读取节点自身的EmSize组件;
  • Val::Rem解析时读取全局RemSize资源,因此在层级树任何位置含义都一致。

构造这两个变体的辅助函数em()rem(),与既有的px()percent()vw()vh()并列。Val还实现了FromStr(L89-L136),现在也能把"1.5rem""2em"之类的字符串解析为对应变体,这在从样式表/序列化数据构造Val时可以直接受益。

字号相关的类型定义位于 bevy_text/src/text.rs:

pub const DEFAULT_REM_SIZE_PX: f32 = 20.0; // L868 pub struct RemSize(pub f32); // L875 pub struct EmSize(pub f32); // L898

DEFAULT_REM_SIZE_PX为 20.0,正好与 0.19 的默认字号px(20)保持一致,这也是默认字号改为rem(1)后行为等价的原因。

迁移点一:resolve 系列方法新增两个参数

由于解析Val现在需要"节点字号"和"根字号"两个基准,以下方法的签名都追加了em_size: EmSizerem_size: RemSize两个参数:

  • Val::resolve
  • Val2::resolve
  • UiPosition::resolve
  • CornerRadius::resolve
  • RadialGradientShape::resolve
  • UiTransform::compute_affine
  • BorderRadius::resolve

调用方式的变化:

// 0.19 let physical = val.resolve(scale_factor, physical_base_value, physical_target_size)?; // 0.20 let physical = val.resolve( scale_factor, physical_base_value, physical_target_size, em_size, rem_size, )?;

在源码中可以确认Val::resolve的新签名(geometry.rs L483-L488)以及Val2::resolve(L1190-L1195)都已带上em_size: EmSize(其后跟随rem_size)参数;UiTransform::compute_affineRadialGradientShape::resolve同样如此(见 ui_transform.rs L69、gradients.rs L615)。

迁移点二:从 ComputedNode 取 em_size / rem_size

如果你是在布局完成之后、针对一个已存在的节点来解析Val(例如自定义box_shadow逻辑),不必自己去追踪字号——ComputedNode新增了两个字段,记录了排版时实际使用的字号值:

  • em_size
  • rem_size

它们的默认值为EmSize(DEFAULT_REM_SIZE_PX)RemSize(DEFAULT_REM_SIZE_PX)(见 ui_node.rs L388-L389)。对已有节点做Val解析时,直接从该节点的ComputedNode上取这两个字段传入resolve即可。

迁移点三:Node 现在要求 EmSize 组件

这是 0.20 中最需要理解的一点:Node现在要求实体上存在EmSize(定义在bevy_text,并在bevy_ui::prelude中重导出),它作为该节点字号,供Val::Em解析使用。其生命周期规则如下:

  1. 节点带有TextFontEmSizeTextFont派生;当TextFontRemSize或渲染目标信息发生变化时会被重新计算。你手动设置的值会保留到下一次重算为止。
  2. 节点没有TextFontEmSize完全由你自己设置,框架不会去动它;默认值为DEFAULT_REM_SIZE_PX(20px)。它与默认RemSize数值一致,但不会跟随RemSize的变化
  3. EmSize的层级传播是应用层的责任,bevy_ui不负责。也就是说,如果你希望子节点继承父节点的字号,需要自己在 App 里做传播系统。release notes 也明确写着:"EmSizeis derived fromTextFontwhen one is on the same entity; propagating it down the hierarchy is left to your app."

迁移点四:GridTrack 的 em/rem 构造器

网格轨道也支持了这两种单位,新增了构造函数与对应的 sizing function 变体:

  • GridTrack::emGridTrack::rem
  • RepeatedGridTrack::emRepeatedGridTrack::rem

它们底层使用新增的MinTrackSizingFunction::EmMinTrackSizingFunction::RemMaxTrackSizingFunction::EmMaxTrackSizingFunction::Rem变体。这两个变体同样出现在 ui_node.rs L1856-L1891 的 min/max sizing function 枚举中,用于按字号倍数定义网格轨道的上下限尺寸。

迁移点五:FontSize::eval 改为接收 RemSize

FontSize::eval的参数类型从裸f32变为RemSize结构体:

// 0.19 let size = font_size.eval(logical_viewport_size, rem_size_px); // 0.20 let size = font_size.eval(logical_viewport_size, RemSize(rem_size_px));

这是一个类型层面的小改动:把根字号包装进RemSize后,字号求值的接口与布局解析接口的单位来源保持了一致的类型表达。

迁移检查清单

升级 0.19 → 0.20 时,可以按以下顺序排查编译错误:

  1. 找到所有Val::resolve/Val2::resolve等调用,补上em_sizerem_size两个参数;针对已排版节点的解析,优先从ComputedNodeem_size/rem_size字段取值;
  2. 为携带Node的实体补上EmSize组件——有TextFont的节点会被框架自动派生/重算,没有TextFont的节点(如纯容器)需要自行设置默认值;
  3. 检查 App 中是否需要新增EmSize向下传播的系统(官方明确这是应用的责任);
  4. 更新FontSize::eval调用,把裸f32包成RemSize(f32)
  5. 网格轨道需要字号单位时,改用GridTrack::em/GridTrack::rem等构造函数;
  6. 若有依赖"默认字号恒为 20px"的逻辑,注意默认字号现在是rem(1)——只有在修改RemSize后才会与旧的硬编码 20px 产生差异。

小结

0.20 的 em/rem 支持让 Bevy UI 的尺寸系统从"像素与视口比例"扩展到了"字号比例":Val::Em随节点自身EmSize缩放,Val::Rem随全局RemSize缩放,且em/rem辅助函数、字符串解析、GridTrack构造器与bsn!语法均已就位。迁移成本集中在resolve系列方法的签名变化与EmSize组件的引入上;只要理解"EmSizeTextFont派生但层级传播交给应用"这一规则,升级路径就非常直接。相关源码入口:geometry.rs、ui_node.rs、text.rs、ui_transform.rs、gradients.rs。

【免费下载链接】bevyA refreshingly simple>项目地址: https://gitcode.com/GitHub_Trending/be/bevy

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/8 21:04:33

开源终端AI编程助手opencode实战:安装配置、skills与插件生态全解析

最近几天我把主力终端AI助手从Claude Code切换到了opencode,中间踩了几个典型的坑,也发现了一些被低估的地方。如果你正在关注开源AI编程助手,想找一个能接多种模型、又有完整插件生态的工具,这篇是我用opencode接手实际开发工作的…

作者头像 李华
网站建设 2026/9/8 21:04:18

Archify:让编码代理生成的代码架构可校验、不腐化

1. 这个项目到底解决的是什么问题编码代理这两年有多火,不用我多说了。你让 Cursor、Claude Code 或类似工具在代码库里加个功能、改个接口,它噼里啪啦一顿操作,几十个文件说改就改。代码能跑,测试能过,看起来一切完美…

作者头像 李华
网站建设 2026/9/8 21:04:16

MT798x路由器固件定制终极指南:7天从新手到专家

MT798x路由器固件定制终极指南:7天从新手到专家 你是否曾经遇到过这样的情况:买回来的路由器功能不够用,想要的功能官方固件不支持,或者网络性能达不到预期?如果你使用的是MT7981或MT7986芯片的路由器,那么…

作者头像 李华
网站建设 2026/9/8 21:02:07

crawl4ai实战:用AI爬虫轻松将网页转为结构化JSON

做数据采集这些年,我最怕的不是网站反爬,而是“爬下来了却要花三倍时间洗数据”。一个商品页,标题在 h1 里,价格在 meta 里,库存状态又藏在某段 JS 变量中,用 Requests BeautifulSoup 不是不能抓&#xff…

作者头像 李华
网站建设 2026/9/8 21:02:05

OpenCV人脸识别门禁系统源码解析与实战指南

简介:面向Python与OpenCV学习者的完整人脸识别门禁系统源码包,适合希望掌握人脸检测、特征提取、实时视频流处理及门禁联动逻辑的开发者。资源共34个文件,包含10个Python脚本、4个XML级联分类器、多张示例图片与测试视频、中文字体及说明文档…

作者头像 李华
网站建设 2026/9/8 21:00:55

AI Agent从Demo到工程落地:开发者不可不知的四大硬骨头

AI Agent 的热度这两年是真的猛,GitHub 上相关项目星标一个比一个高,技术社区里晒 Demo 的帖子也随处可见。一个聊天窗口接上大模型,再配几个工具调用,就能演示“自动写周报”“自动查天气”“自动订机票”之类的效果,…

作者头像 李华