Freeze content on window resize:窗口缩放时锁定阅读列与阅读位置

前言

在 DeepSeek Harness(DSH)Web GUI 里读长回答时,若一边读一边拖窗口边缘,段落会重新换行,眼睛所在的那一行往往就「跑」了。这不是滚动条误触:对话列宽度会随窗格变化,浏览器仍用像素保存 scrollTop,换行后同一数值不再指向同一段文字。DSH 自带的 resize 处理会跟尾或重探当前轮次,但不会把读者原先的阅读锚点拉回来。

下面介绍社区客户端插件 freeze-content-on-window-resize(维护者 nnnanann)。它在窗口缩放时锁定对话阅读列宽度,并在缩放或缩放后尽量保持阅读位置,减少长文重排带来的跳读。

这是什么

freeze-content-on-window-resize 是面向 DSH Web GUI 的客户端插件:锁定正在阅读的对话列宽度,并在窗口 resize 时补偿阅读锚点,使长回答不再因窗宽变化而整段重排。

DSH 生态强调「一切皆插件」;SkillHub 等社区目录独立于 DeepSeek / 幻方,并非官方应用商店。安装前建议自行查看源码与许可证——插件随当前 DSH 进程在本地 Web GUI 中运行,权限与宿主一致。

背景:为何会「读丢行」

在 DSH 0.2.0-rc.2(win32)上验证过的行为大致如下(插件依赖 DSH 稳定 data-* 属性,而非哈希 class,较新版本通常仍可工作):

对话列在滚动容器内,内容宽度由窗格与 ResizeObserver 共同决定。未在本地存过拖拽宽度时,宽度大致为 clamp(680px, 0.64 × pane, 920px),在约 1063–1438px 窗格范围内会随窗口逐步变化,每一步 resize 都可能重排。若曾拖拽过宽度,则使用 localStorage["dsh.conversation.contentWidth"] 中的偏好,直到窗格放不下才再缩小。

与此同时 scrollTop 仍是旧像素位置,重排后视觉锚点偏移。README 中给出过测量示例:强制变窄约 140px 时,阅读行可偏移约 2417px;启用锚点补偿后可回到 0px 偏移(方法见仓库 docs/self-test.md)。

核心功能

机制 效果
锁定内容宽度 对已挂载的阅读列用同一像素宽度固定 width / min-width / max-width(!important),换行不再随窗口变化;窗变窄时出现横向滚动而非重排。
保持阅读位置 每列维护 live anchor(阅读行上的 data-chat-anchor-key 及其相对视口顶部的偏移);resize 或 zoom 后跨两帧动画再加一次延迟 pass 重新对齐。

补充说明(与 README 一致):

  1. 视图处于「跟尾」状态([data-chat-following-tail])时,锚点补偿会退让,由 DSH 自带跟尾逻辑负责;宽度锁定仍生效。
  2. 侧栏内嵌的对话 transcript 仍用面板自身宽度,不受本插件对主阅读列的处理影响。
  3. 锁定后,加宽窗口不会再自动加宽阅读列(与 stock DSH 在 clamp 未饱和时会变宽不同)。这是刻意取舍:宽度一次选定后保持不变;要改宽度需用面板 Width 或 DSH 自带拖拽手柄。

依赖与环境:

  • 需要带 Web GUI 的 DSH(桌面窗口或 dsh web)。
  • 无额外 npm 依赖、无构建步骤;客户端入口为已提交的 client/client.js(window.__ModuleLoader__.load 手写 bundle)。

安装与启用

profile 名对应 ~/.dsh/profiles/ 下目录;文档示例使用 desktop,请换成你自己的 profile。

推荐方式(无需手动 clone):

dsh plugin --profile desktop add github:nnnanann/Deepseek-harness-freeze-content-on-window-resize

dsh plugin add 会把参数转给 pnpm,pnpm 支持的 spec 均可尝试。若当前 DSH 构建不接受 github: spec,可从本地 checkout 使用 link:(README 亦给出 git clone + link: 示例,此处不展开 clone 步骤)。

安装后会写入 profile 的 package.json、追加 dsh.profile.bundles 中的 freeze-content-on-window-resize 并完成安装。已打开的 GUI 页面可热加载,一般无需重启 DSH。

卸载:

dsh plugin --profile desktop remove freeze-content-on-window-resize

典型用法

界面控件

窗口右下角有一个约 26px、半透明为主的锁定按钮(fixed 于窗口,侧栏打开时可能叠在侧栏上;可在面板中隐藏)。点击打开设置面板,主要项如下:

面板项 含义
Lock content width / 锁定内容宽度 总开关;关闭则恢复 DSH 默认行为。
Width / 宽度 数字或预设 620 / 680 / 748 / 820 / 920;首次运行会采用 DSH 当前内容宽度,避免安装瞬间跳变。
Keep reading position / 保持阅读位置 锚点补偿开关。
Show this control / 显示此控件 隐藏右下角按钮。
Reset / 恢复默认 恢复默认设置。

面板文案随 DSH UI 语言;插件自带中英文词典,其他语言时回退中文。开关下方灰字说明权衡:锁定后文本不再因窗宽重排,窗变窄则横向滚动。

快捷键

文本输入框聚焦时快捷键不生效:

快捷键 作用
Alt+Shift+L 切换宽度锁定
Alt+Shift+W 循环预设宽度

DSH 自带的列宽拖拽(cursor: col-resize)仍可用:按下拖拽会释放锁定,松开指针后以拖拽宽度作为新的锁定宽度。

配置存储

设置保存在页面 localStorage 的 freeze-content-on-window-resize:config;width: 0 表示「采用 DSH 自身宽度」,首次运行会解析并写入实际值。示例:

{ "lockWidth": true, "width": 748, "keepPosition": true, "showControl": true }

控制台诊断

在 DevTools 控制台:

__fcwr.status()
__fcwr.realign()
__fcwr.dispose()

启动时控制台会输出一行当前语言日志,例如锁定列宽或 width lock off。另有 freeze-content-on-window-resize:boot stamp 记录 revision、列宽与 anchor 等,便于排查。

适用场景与注意

适合: 经常在 DSH Web GUI 中阅读长回答、需要分屏或频繁调整窗口大小、且希望换行稳定、少丢阅读位置的开发者或日常用户。

注意:

  1. 锁定宽度后,单纯拉大窗口不会自动变宽阅读列;需 consciously 调整 Width 或拖拽 DSH 手柄。
  2. 窄窗下可能出现横向滚动,这是锁定换行的直接结果。
  3. 插件仅在客户端 Web 层生效,不修改 DSH 服务端;安装与更新请使用官方 README 中的 dsh plugin 命令,并核对 MIT 许可与源码。
  4. 开发验证基线为 DSH desktop 0.2.0-rc.2;其他版本若 DOM 或属性有变,需自行验证。

实现要点(简述)

插件不依赖哈希 class,主要使用 DSH 稳定属性,例如 [data-chat-flow](列)、[data-conversation-scroll](外层滚动)、[data-composer-seat]、[data-chat-anchor-key]、[data-chat-following-tail]。宽度变量仅回写到同时持有列与相关上下文的元素,避免误伤侧栏 transcript。

结尾

freeze-content-on-window-resize 用「锁列宽 + 锚点补偿」应对 DSH 对话区在 resize 时的重排与 scroll 错位,适合长文阅读场景。安装与配置以仓库 README 为准。

  • 目录页:https://www.skillhub.cn/plugins/nnnanann/Deepseek-harness-freeze-content-on-window-resize
  • GitHub:https://github.com/nnnanann/Deepseek-harness-freeze-content-on-window-resize
羽毛球分组比赛记分
小程序二维码

欢迎使用《羽毛球分组比赛记分》微信小程序

Xiaoye