Files
ycode/docs/reference/workbuddy-chat-layout.md
T

132 lines
11 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# WorkBuddy 对话区前端布局实测
> 2026-10-08补充:[最新原生内层文字与布局审计](ygent-workbuddy-render-audit-2026-10-08.md)。下文外层用户气泡13px、输入容器14px不是实际文字字号;本机Slate内层两处实际均15px,应以最新审计为准。
验证对象:WorkBuddy AI 5.7.6、Windows、主窗口 1200 × 762 CSS px、DPR 1。
证据来自真实页面 CDP computed style、元素矩形、内联样式及安装包 CSS。
这是一个窗口与会话下的实测,不代表所有分辨率和用户字号设置。
## 字体规则
对话正文不是每级字号各自写死 `px`。Markdown 先接入根字号和行高 token,再由段落与标题按相对比例排版;运行时显示出来的像素值只是当时 token 的计算结果。输入框属于另一套控件样式,当前 CSS 确实单独声明了 `14px`。
| 元素 | 运行时实测 | CSS 规则 |
|---|---:|---|
| Markdown 根节点 | 当前解析为 17.143px / 30px | `font-size: var(--cr-md-root)`;行高 `var(--cr-md-line-height, 1.75)` |
| Markdown 段落 | 当前解析为 15px / 26.25px | `font-size: .875em`,继承 1.75 行高 |
| Markdown 一级标题 | 由 token 控制 | `font-size: var(--cr-md-h1-font-size, 1.25em)` |
| Markdown 行内代码 | 按父级字号 | `font-size: 1em` |
| Markdown 表头 | 当前解析为 15px / 26.25px,字重 600 | 单元格横向 padding 12px;浅色表头实测 `#f7f7f7` |
| 输入区 | 当前解析为 14px / 21px | `.cr-input-box` 声明 `font-size:14px; line-height:1.5` |
| 输入编辑器 | 高度 64px,padding 横向 16px | `.cr-input-editor-host` `min-height:64px; overflow-y:auto` |
Markdown 组件声明 `--cr-md-root: var(--cb-md-root, 16px)`,当前主题解析为
`--cb-md-root: 17.143px`。HTML 根字体为 16px,页面 zoom 和 visual viewport scale 均为 1。
本次 15px 段落是根字号乘 `.875em` 的计算结果,不能反推为源码把段落固定写成 `15px`,
也不能归因于 viewport 缩放。字号变量的上游已在组件 bundle 中找到,具体的六级调节规则见下节。
实际正文段落间距为 12px;代码块实测使用 monospace、12.857px / 22.5px 行高、
横向 padding 16px,并限制内部滚动。Ygent 当前默认档的 Markdown 根字号、段落比例、
行高与代码字号已按上述规则设置;用户气泡仍单独采用 13px / 19px。
## 全局字号控制
`renderer/assets/ui-docs-viewer-veG3wQhz.js` 中有统一的字号级别管理器,作用超过 Markdown:
正文、标题、说明文字、代码、按钮文字和按钮高度都接入它。
级别保存在 `localStorage` 的 `agent-ui-font-size-level:v2`,并同步到
`config.preference.fontSizeLevel`。有效级别为 1 到 6;没有有效保存值时默认为 2。
每级同时更新根 Markdown 字号和全局偏移量:
| 级别 | 根字号 token `--cb-md-root` | 全局字号偏移 |
|---:|---:|---:|
| 1 | 16px | -1px |
| 2(默认) | 17.143px | 0px |
| 3 | 18.286px | +1px |
| 4 | 20.571px | +2px |
| 5 | 22.857px | +2px |
| 6 | 26.286px | +2px |
`--wb-font-body-size`、`--wb-font-caption-size`、标题和代码等设计 token 用各自的 base size
加全局偏移计算。全局 token 偏移夹在 -1 至 +2px,避免级别 5、6 把紧凑控件撑大过多;
按钮高度再按更新后的行高和垂直 padding 重算。
旧 CSS 中直接写为 `font-size: 13px` 的规则也会参与字号调节。管理器扫描可读的样式表,
按级别注入 `max(8px, calc(13px + var(--cb-font-size-offset) * 1px))` 覆盖规则。
它保留 `@media` 分组,观察后续新增的样式表,并排除 `.cb-font-size-fixed` 及其子孙节点,
以便明确声明固定字号的控件不随全局级别改变。
Windows 上可用 `Ctrl+-` 降一级、`Ctrl++` 升一级、`Ctrl+0` 恢复默认。级别限制在 1 到 6。
切换时派发 `cb-font-size-change` 和 `cb-font-size-level-change` 事件,让组件刷新。
源码会同时出现字体 token、相对 `em` 和少量固定 `px`:全局设置更新设计 token,
并兼容旧组件里的固定字号。
## 宽度与主布局
在当前 1200px 窗口中,左侧栏为 280px,主内容区为 920px。对话历史和输入区各自在主内容区居中,并使用相同的 832px 上限:
- `.cr-message-list__content` 运行时内联 `max-width: 832px`,源码使用 `width:100%; max-width:100%; margin-inline:auto`。
- 对话内容区左右 padding 为主题变量 `--cr-message-list-content-inline-padding:40px`。832px 外框扣除 80px 后,消息正文列为 752px。
- 输入区外框上限同为 832px,外框左右各 padding 24px,输入控件宽度为 784px。
- 小于 832px 的可用主列时,`width:100%` 收缩外框,正文与输入仍分别保留自己的横向 padding。布局跟随内容区宽度,不依靠 viewport 单位设定字体。
- 对话主列是 flex 布局。消息列表 `flex:1; min-height:0; overflow-y:auto`,输入区 `flex-shrink:0` 固定在底部;这样滚动发生在历史列表内部,长内容不会把输入区挤出窗口。
- 输入编辑区设置最小高度,并通过纵向滚动承载增长内容;工具栏单独 flex 布局、`flex-shrink:0`,操作项不会跟着编辑内容收缩。
Ygent 对应使用同一内容列:在 1200 × 762 窗口、280px 侧栏和 10px 消息滚动条下,832px 对话外框居中后,消息正文列落在 `x=359..1111`(752px)。助手头像行、回答正文和用户气泡均对齐这条列;输入框外框落在 `x=348..1132`(784px),其编辑器和工具栏分别保留 64px 与 56px 高度。窗口窄于内容上限时,消息列跟随可用宽度收缩,窄屏左右内边距为 16px。
实测 DOM 层级中,对话列和输入区都受 832px 居中容器约束,但消息、输入和工具栏是独立组件。这个边界让两边 padding 与窄窗收缩策略各自清晰。
## 响应策略
- 主列采用 `width:100% + max-width + margin:auto`;用可用宽度与最大宽度自然收缩。
- `.cr-message-list` 声明 `container-type:inline-size`,具备查询容器的能力。当前对应 CSS 文件没有 `@container` 规则,不能仅凭声明推断对话区已有完整的容器断点体系。
- 对话输入工具栏有 `width <= 320px` 的局部断点,在极窄宽度下隐藏次要 context-usage 标记,给常用操作留空间。
- 主内容 CSS 的另一个欢迎页容器 `.chat-container--welcome` 默认上限 848px,在 viewport 至少 1681px 时扩到 1008px;这是不同容器的规则,不能跟本次运行页面的 832px 对话列混为一谈。
- 组件 CSS 使用 `prefers-reduced-motion` 减少消息列表进出动画。
## 消息气泡、widget 与输入区
同一窗口的当前会话快照实测:
| 元素 | 运行时规格 |
|---|---|
| 助手头部 `.cr-agent__header` | 752px 内容宽;24.5px 高;24px 圆形标识、10px 间距;名称 14px / 24.5px、字重 600;下方间距 12px |
| 完成状态 `.cr-collapse__header` | 文案 `已完成 3m2s`;15px / 26.25px、三级文字色、宽度随内容;12px 箭头与 8px 间距 |
| Markdown 根 `.cr-markdown` | 字号 17.143px / 行高 30.0002px(当前 2 级);段落按 `.875em`,实测 15.0001px / 26.2502px |
| 列表 `.cr-markdown ul` | 15.0001px / 26.2502px;左缩进 21.4502px;列表后间距 16px;列表项间距 4px |
| 表格单元格 `.cr-markdown th/td` | 15.0001px / 26.2502px;padding `8px 12px`;表头底色 `#f7f7f7` |
| 代码块 `.cr-markdown pre` | 12.8573px / 22.5002px;padding `12px 16px` |
| 用户气泡 `.cr-self-bubble` | 13px / 19px;`#f2f2f2`;padding `8px 12px`;圆角 `16px 16px 0`;最小宽 40px、最大宽 100%、最大高 310px,内部滚动 |
| 用户消息工具栏 `.cr-toolbar` | 相对用户气泡框架绝对定位在底部;默认透明;时间 14px / 20px,含复制和编辑按钮 |
| 表格操作 `.cr-message-quote-table-menu` | hover 时显示于表格右上角;菜单 116×38px,按钮 106×28px;点击把原表格 Markdown 加入输入草稿 |
| widget 卡 `.cr-widget-card` | 正文列宽 752px;边框 `1px solid #ebebeb`、圆角 16px、纵向 margin 8px |
| widget 内容 `.cr-widget-body` | padding `12px 16px`;当前 iframe 宽 718px,高度随内容变化 |
| widget iframe | `sandbox="allow-scripts"`,不含 `allow-same-origin`;CSP 允许内联脚本与指定 CDN |
| 输入容器 `.cr-input-container` | `x=348, y=592, 784×134px`;白底、`1px solid #e6e6e6`、24px 圆角、两层轻阴影 |
| 输入编辑区 `.cr-input-editor-host` | `x=349, y=605, 782×64px`;横向 padding 16px;字号 14px / 21px |
| 输入工具栏 `.cr-input-toolbar` | `x=349, y=669, 782×56px`;padding 12px;按钮 32px |
| 禁用发送按钮 | 32px 圆形;图标圆底填充 `rgba(0,0,0,.2)` |
widget 的高度由 iframe 内容决定。SVG 根据自身 viewBox 呈现比例,HTML 图表按内部容器高度扩展;iframe 向父层报告尺寸,宿主验证来源并限制最大值。
## 对 Ygent 的参考价值
1. 给对话消息和输入区一个共享的居中最大宽度,再分别配置内边距。避免消息列与输入框在宽屏各自漂移。
2. 用 `min-width:0`、`min-height:0`、flex shrink 和列表内部 `overflow-y:auto` 明确滚动容器。窄窗或长内容时,输入区仍留在底部。
3. 把 Markdown 基准、段落倍率、行高、输入区字号做成角色明确的 token。Ygent 的默认 Markdown 规则与本次实测一致;用户气泡和输入区按各自控件规格管理。全局字号应明确级别、上下界、持久化、组件更新方式及固定字号例外。Ygent 六档根字号跟随 WorkBuddy,常规控件偏移在第 5、6 档封顶为 +2px。
4. 在真正受限的控件上做局部响应。窄宽时优先收起次要工具标记,别先整体缩小所有字号。
5. 以运行时 computed style 验收主题变量、Electron zoom 和实际像素;只读静态 CSS 很容易漏掉主题宿主注入的 token。computed `px` 是实测结果,不是 token 定义本身。
## 证据与局限
- 运行时快照与截图保存在用户私有目录 `%USERPROFILE%/.ygent/imports/workbuddy-debug-20261008/`,不放进仓库。
- 主要组件 CSS:`renderer/assets/lib-chat-ui-B-axvvx6.css`。
- 字号管理器:`ui-docs-viewer-veG3wQhz.js`,包括级别表、存储键、快捷键和旧式 `px` 样式覆盖。
- 正文段落规则:`.cr-markdown` 使用主题根字号和 1.75 行高,`.cr-markdown p` 使用 `.875em`,标题也使用相对字号 token。
- 输入布局规则:`.cr-input-box` 14px / 1.5;编辑器最小高 64px;输入容器运行时 inline `min-height:96px`。
- 当前会话主体宽度 832px 来自运行时 inline style;CSS 文件里 `.cr-message-list__content` 只声明 `max-width:100%`。具体控制该 inline 值的组件逻辑尚未追踪。
- DOM 是虚拟列表,仅包含当前已挂载部分。离开视口的消息矩形可以是负坐标,不能按快照节点数估算完整会话。
- 点击窗口不同宽度进行重复采样前,先另建输出目录。复测时同时记录 viewport、DPR、Electron zoom、主题与相关主题变量。
采集过程见 [运行时调试 SOP](workbuddy-cdp.md),可续接会话数据见 [对话导入说明](workbuddy-reference-import.md)。