前言¶
DSH(DeepSeek Harness)的 ChatView 在长会话场景下会出现滚动和重绘变慢的问题。原因是它把每一条消息节点全量挂进 DOM,既没有虚拟滚动,也没有 content-visibility。随着消息条数增多,浏览器需要为屏外元素执行 style、layout、paint,拖累滚动流畅度。
本插件不改变渲染逻辑,只是往页面里注入一条 CSS 规则,让视口外的消息正文与块级公式跳过这些计算,由浏览器自己决定什么时候真正渲染。
是什么¶
dsh-chat-perf-css 是 DSH 长会话渲染减负插件。它只做一件事:注入一条 CSS 规则。
| 项 | 说明 |
|---|---|
| 维护者 | Light-EI |
| 分类 | 客户端 |
| 仓库 | https://github.com/Light-EI/dsh-chat-perf-css |
| 星标 | 2 |
| 许可证 | MIT |
插件通过 content-visibility: auto 让屏外消息正文(约 320px 占位高度)和块级公式(约 90px 占位高度)跳过 style、layout 和 paint,减少长会话滚动时的 CPU 和 GPU 开销。
核心功能¶
注入的两条 CSS 规则¶
[class*="_markdown_"]:not([class*="_icon_"]):not(svg){content-visibility:auto;contain-intrinsic-size:auto 320px}
.katex-display{content-visibility:auto;contain-intrinsic-size:auto 90px}
- 第一条命中消息正文容器:前端使用 CSS-module 类名
_markdown_<hash>_<line>,规则只匹配稳定的 key 部分,不匹配 hash。 - 第二条命中块级公式:给
.katex-display加上同样的属性。 - 两条规则都排除文件类型图标组件(它们也带
_markdown_类,挂载在<svg>上),避免占位高度过大。
工作原理¶
插件只注入 CSS,不调用 DSH 插件 API,不注册服务,不监听事件。当某条消息进入视口时,浏览器会为它执行完整的渲染流程;离开视口后,它会被视为“已渲染”,占位高度会被替换为真实高度。这样,长会话滚动时只需要处理视口内的元素。
它不会做什么¶
- 不解决流式生成时公式反复重算(那是渲染逻辑本身的事)。
- 不修改 KaTeX 的输出选项,不动 MathML。
- 不碰模型、工具、凭据、系统提示词、会话日志或压缩逻辑。
- 无网络请求、无 localStorage、无定时器、无 MutationObserver。
- 零依赖:不声明
dependencies/peerDependencies,CSS 在运行时由插件自己拼出来。
已知副作用¶
| 现象 | 说明 |
|---|---|
| 滚动条长度是估算值 | 屏外部分用固定占位高度估计,渲染过之后会记住真实高度。短消息会偏长、长代码块会偏短,滚过一遍即收敛 |
| 滚到未渲染区可能轻微跳动 | 该区域首次进入视口才真正渲染 |
| 会话内搜索跳转先落到估算位置 | 依赖 scrollIntoView,命中占位高度,渲染后位置会被校正 |
| 把整页渲染成图或 PDF 的工具可能漏掉屏外内容 | 打印 / 长截图 / 导出类工具沿用视口判断 |
| toast 位置可能轻微偏移 | toast 用锚元素 getBoundingClientRect() 定位,锚点在屏外时取到占位矩形 |
| 浏览器 Ctrl+F 能搜到,但首次搜索可能卡一下 | 命中后会被强制渲染,定位可能需要再滚动校正一次 |
安装与启用¶
DSH 的「添加插件」接受三种输入:包名、GitHub 仓库地址、本地目录。
方式一:通过仓库地址安装(推荐)¶
在 DSH 的「添加插件」里粘贴仓库地址:
https://github.com/Light-EI/dsh-chat-perf-css
安装器会把它记成 github:Light-EI/dsh-chat-perf-css,装的是 main 分支的最新代码。本仓库的规则是:插件代码只在发版时改动,平时在 dev 上开发,发版时合并进 main 并打 tag。所以这条路装到的插件行为与最新正式版一致;main 上可能夹着还没发版的文档改动(不影响插件行为)。
方式二:通过 Release 下载安装¶
使用 Release 附带的预构建包,同样是“填进去就能装”,但走的是 HTTPS 下载而不是 git:
https://github.com/Light-EI/dsh-chat-perf-css/releases/latest/download/dsh-chat-perf-css.tgz
这个地址永远指向最新正式版(资产名固定,不随版本号变),也可以离线下载后用命令行安装。
方式三:手动安装(离线、没有仓库权限,或不走插件管理器时用)¶
- 解压 Release 里的
dsh-chat-perf-css-v<版本>.zip(例如…-v1.0.4.zip),把dsh-chat-perf-css目录放进<profile>\plugins\dsh-chat-perf-css\。 - 在该 profile 的
package.json里:
-dependencies增加"dsh-chat-perf-css": "link:./plugins/dsh-chat-perf-css"
-dsh.profile.bundles数组增加"dsh-chat-perf-css" - 在 profile 目录跑一次
pnpm install(建立node_modules链接并更新 lockfile)。 - 重开 DSH 窗口。
绕开安装器时这两步必须都做:只写
dependencies会把包装上但不会被加载,页面没有任何变化。
升级¶
- 用仓库地址(不带
#)或#semver:^1装的:在插件管理器里对它执行一次更新就行(命令行等价:dsh plugin --profile <profile> update dsh-chat-perf-css)。 - 用
#v1.0.4这类锁定写法装的,不会自己动 —— 要把安装地址里的 tag 换成新的再装一次。 - 手动安装的,重新解压覆盖
plugins\dsh-chat-perf-css\目录即可。
卸载¶
- 在插件管理器里卸载即可。
- 手动装的按反方向来:从
dsh.profile.bundles去掉这项、从dependencies去掉这条,跑pnpm install,再删掉plugins\dsh-chat-perf-css\目录。
典型用法与验证¶
装完即生效,不需要再改任何配置。安装器的动作单位是 bundle,会把 dependencies 与 dsh.profile.bundles 一起写好。
在 DSH 窗口的开发者工具里执行(用的是插件那条完整选择器,不要只看第一个匹配元素):
const els = document.querySelectorAll('[class*="_markdown_"]:not([class*="_icon_"]):not(svg)');
`匹配 ${els.length} 个,生效 ${[...els].filter(e => getComputedStyle(e).contentVisibility === 'auto').length} 个`
- 「生效」数大于 0 即正常;
- 「匹配」是 0,说明前端类名变了、规则没命中,页面只是没有优化;
- 不要用
document.querySelector('[class*="_markdown_"]')只看第一个:第一个可能恰好是被规则排除的附件图标(<svg>那个.md图标也带_markdown_类),会返回"visible"让你误以为没生效。
适用场景与注意¶
适用场景¶
- 长会话(几百条消息以上)滚动变卡。
- 消息中包含大量 Markdown 正文和块级公式。
- 愿意接受滚动条长度是估算值、首次进入未渲染区可能轻微跳动等小副作用。
注意事项¶
- 插件以当前 DSH 进程权限运行,安装前应检查源码与许可证(MIT)。
- DSH 官方一旦加入虚拟滚动(只把视口附近的消息节点挂进 DOM),本插件的收益基本归零,届时应卸载它。
- 插件只命中依赖前端 CSS-module 类名
_markdown_<hash>_<line>。DSH 前端一旦改名或改结构,规则会静默失效:页面一切正常,只是没有优化。 - 需要 Chromium 85+(
content-visibility)。Electron 与新版 Chrome/Edge 均满足;Firefox 125+、Safari 18+ 起支持;老版本浏览器会忽略这两条规则,退化为“没有优化”,不会出错。
总结¶
dsh-chat-perf-css 是一个轻量级、零依赖的 CSS 注入插件,专注于解决 DSH 长会话滚动卡顿的问题。它不改变渲染逻辑,只是让屏外元素跳过 style、layout 和 paint,由浏览器决定何时真正渲染。在长会话场景下,它能让滚动更流畅;在虚拟滚动出现后,它自然就该退场。
插件目录页与源码仓库:
- 目录页:https://www.skillhub.cn/plugins/Light-EI/dsh-chat-perf-css
- GitHub:https://github.com/Light-EI/dsh-chat-perf-css