xterm.js 6 的滚动条不是原生的,CSS 全部失效是正常的
在某个内嵌了 Web 终端的桌面应用里,我需要隐藏 xterm.js 的滚动条,然后自己画一根始终可见的条。按照常规思路,先试 CSS——结果花了整整一个小时在一个根本打不到目标的地方反复调。
现象
往终端区域扔了以下所有招数,一条都没用:
/* 尝试 1:webkit 专用伪元素 */
.xterm-viewport::-webkit-scrollbar { display: none; }
.xterm-viewport::-webkit-scrollbar-thumb { background: transparent; }
/* 尝试 2:标准属性 */
.xterm-viewport { scrollbar-width: none; }
/* 尝试 3:appearance */
.xterm-viewport::-webkit-scrollbar { -webkit-appearance: none; }
/* 尝试 4:overflow 截断 */
.xterm-viewport { overflow: hidden; }在 macOS WKWebView 环境里,那根灰色滚动条依然在滚动时出现,停止滚动后自动淡出——活脱脱一副系统原生 overlay 滚动条(NSScroller)的样子。
根因
这里有一个反直觉的事实:xterm.js 6.0 完全重写了滚动条,改用自己的 DOM 节点来渲染,根本不是浏览器原生滚动条。
用 DevTools 展开终端节点,实际结构是这样的:
<div
role="presentation"
aria-hidden="true"
class="invisible scrollbar vertical fade"
style="position:absolute; width:14px; height:735px; right:0; top:0;"
>
<div
class="slider"
style="position:absolute; top:431px; height:289px; width:14px;
transform:translate3d(0,0,0); contain:strict;"
></div>
</div>- 外层是
div.scrollbar.vertical.fade,有一个 JS controller 负责在滚动时移除invisible类、停止后再加回去并触发 fade 动画——这就是「滚动时出现、停止后消失」的根源,和系统 overlay 表现一模一样,却完全是两码事。 - 内层
div.slider是滚动条拇指(thumb),通过transform + contain:strict定位。
因为它是普通 <div>,所有针对原生/WebKit 滚动条的 CSS 机制(::-webkit-scrollbar、scrollbar-width、overflow、-webkit-appearance)完全看不见它。
看到「滚动时出现、停止后消失」的灰色条,第一直觉是 macOS overlay 滚动条,然后开始在 ::-webkit-scrollbar / overflow / scrollbar-width 这几个工具里反复试——但 xterm.js 6 的这根条跟系统完全无关,这些工具的作用域根本不覆盖它,花再多时间也是零效果。
正解
先用 DevTools 右键 → Inspect 确认是 div.scrollbar > div.slider,然后直接对着这两个类打:
/* 隐藏 xterm 6 自渲染的滚动条(限定容器,不影响其他地方) */
.term-container .scrollbar,
.term-container .slider {
display: none !important;
}如果还要防止非 macOS 平台出现原生滚动条:
/* 可选:抑制 viewport 上可能存在的原生滚动条 */
.term-container .xterm-viewport {
overflow: hidden;
}这不会破坏滚轮滚动——xterm 6 的滚轮事件走的是 onRequestScrollLines → scrollLines(buffer ydisp),和 DOM scrollTop 无关。
如果要换成自己的始终可见滚动条,思路是:监听 term.onScroll / term.onRender,从 term.buffer.active.baseY、term.buffer.active.viewportY、term.rows 三个值算出比例,然后用 term.scrollToLine(n) 响应拖拽。
不要碰 ::-webkit-scrollbar 系列。找到 div.scrollbar > div.slider 直接 display: none !important,隐藏立即生效,两行 CSS 解决。
一句话外卖
滚动条 CSS 全部失效时,先 Inspect Element——现代库(xterm 6、各类虚拟列表/Grid 库)越来越多地自己渲染 DOM 滚动条,原生 CSS 机制对它们毫无作用,一次检查胜过无数轮猜测。