daoyu1993-lab/dsh-plugin-sidebar-polish ↗★ 0
dsh-plugin-sidebar-polish
Polish the DSH left sidebar: drop the brand row, redraw New Session as a panel row, unify row heights and indents, tune the fill for dark and light, pin the collapse toggle, add a settings entry, and mark idle sessions. 适合需要精简侧边栏布局、提升界面整洁度与对齐美感的视觉强迫症用户。
Install
npx -p @deepseek-ai/dsh dsh plugin --profile web add github:daoyu1993-lab/dsh-plugin-sidebar-polishREADME
Read the full README ↗dsh-plugin-sidebar-polish
去掉 DSH 左侧栏的顶部品牌行,让工作区/会话列表整体向上补位;
把**「新会话」按钮改画成与它下面那组全局面板行(插件 / Skill-MCP / 自动化任务 / 乔木 RSS)
同款的列表行(此前这个按钮被整条隐藏,现在回来了:新会话 就是这份列表的第一行);
把面板行 / 工作区行 / 会话行的 pill 与文字对齐到同一条线;
并给无状态(idle)的会话行**左侧补一个与官方彩色状态点同尺寸的灰色圆点
(官方只在运行 / 待审批 / 刚完成时画点,无状态行留空)。

「新会话」按钮改造前后(上排静止、下排 hover):

| 官方原版 | 现在 | |
|---|---|---|
| 顶部品牌行(鲸鱼 + deepseek HARNESS) | 有 | 移除 |
| 「新会话」按钮 | 有(38px 独立卡片:0.5px 描边 + elevated 半透明底 + 内容居中 + 下外边距 12px) | 保留,改画成面板行同款的一行(32px 胶囊 / 16px 图标 / 图标→文字 8px / 文字 40px / 下外边距 4px / 无描边无底色) |
| 折叠开关(面板图标) | 展开态在侧栏最右(x = 240..268)、收起态在红绿灯右侧(x = 88..116),两态之间横跳 152px | 两态都钉在红绿灯右侧(x = 88..116) |
| 列表位置 | 从第 ~110px 开始 | 直接顶到顶部 |
| 面板 pill 左右边距 | 14px | 8px(与列表 pill 对齐) |
| 侧边栏左右内边距 | 12px | 8px |
| 图标→文字间距(面板 / 工作区 / 会话) | 8 / 6 / 4px | 8 / 8 / 8px |
| 「工作区」区段标题 x | 16px | 16px(与图标同线) |
| 行高(面板 / 工作区 / 会话 / 更多会话) | 36 / 34 / 32 / 28px | 全部 32px(含新会话行与「工作区」标题行) |
| 工作区与工作区之间 | 4px(组内行距的 2 倍) | 8px(组内行距的 4 倍,分组一眼可辨) |
| 侧边栏底色(暗色) | 基色 #1b1b1c + 顶部淡蓝/底部淡紫渐变 | 基色 #151517(= 对话区)+ 去掉渐变,50% 半透明保留 |
| 侧边栏底色(亮色) | 基色 #f9fafb,40% 不透明 | 基色 #ffffff(= 对话区)+ 不透明度 90%,渐变去掉;实测 rgb(227,227,228) → rgb(248,248,250)(对话区 255,255,255) |
| 激活工作区的文件夹图标 | 蓝色强调 rgb(122,170,255) | 与行文字同色 rgb(249,250,251) |
| 无状态(idle)会话行的左侧 | 空的(只有运行/待审批/刚完成才有圆点) | 补一个 6px 灰点(官方 idle 状态色,与彩色点同尺寸同心) |
| 文字左对齐线(新会话 / 面板 / 工作区 / 会话) | 居中 / 46 / 42 / 40px | 40 / 40 / 40 / 40px |
| 设置行(头像 + 名字)右侧 | 空的(整行本身就是账号菜单的触发按钮) | 补一个齿轮入口:真实按钮、自己的热区、点击直接打开设置面板;盒子与「新建工作区」按钮完全重合(28×28,列宽 − 8px 那条线) |
| 工作区/会话列表、设置行、面板入口 | 保留 | 保留(原样) |
| 收起后的 56px 轨道展开按钮 | 有 | 保留 |
| 「展开其余 N 个会话」按钮 | 28px 高 / 12px 字 / hover 无底色 / 文案「展开其余 N 个会话」 | 32px 高 / 14px 字 / hover 同款胶囊 / 文案「更多会话」 |
预览页 preview/compare.html 由 tools/build-preview.mjs 在本地生成(不随仓库分发:页面内联了
DSH 官方样式表,生成方式见「自检」一节的第 0 步),生成后可直接在浏览器打开;
细粒度对齐见 preview/align.png,新会话行见 preview/new-session.png。
图中侧边栏外壳的 CSS 与 DOM 结构取自真实包,会话条目为示意内容。
安装
插件目录就是本目录。两种装法二选一,不要同时启用(会插入两行同名插件):
# 本地目录(本仓库 clone 下来之后)
dsh plugin --profile desktop add "link:$PWD"
# 或直接从 GitHub
dsh plugin --profile desktop add "github:daoyu1993-lab/dsh-plugin-sidebar-polish"
它会把这个包加进 profile 的 dependencies 与 dsh.profile.bundles,并在 node_modules/ 下
建一个指向本目录的软链接(登记的是 link: 依赖,pnpm install 不会把它清掉),
所以在这里改 client.js 会被热更新直接读到。应用运行中也能安装。
// ~/.dsh/profiles/desktop/package.json
"dependencies": {
"dsh-plugin-sidebar-polish": "link:"
},
"dsh": { "profile": { "bundles": [ ..., "dsh-plugin-sidebar-polish" ] } }
验证装载点:
dsh --profile desktop --dump-config | grep sidebar-polish
在本机(macOS 桌面版)实测核实:
- 运行中应用的实时模块图里包含本插件(
/plugins/eventsSSE 的graph事件); - 客户端产物可下发:
/plugins/??dsh-plugin-sidebar-polish/client.js&rev=…返回 200,内容与本目录文件一致; - 安装后没有产生新的崩溃日志。
页面需要刷新一次(⌘R)才能看到效果 —— 当前页面是在插件加入之前加载的。
卸载 / 回滚
dsh plugin --profile desktop remove dsh-plugin-sidebar-polish # 需完全退出 App
或直接编辑 ~/.dsh/profiles/desktop/package.json:从 dependencies 与
dsh.profile.bundles 里各删掉一行,重启应用。插件本身不改任何官方文件,
删掉之后界面立即回到原样;样式表由 ctx.effect 管理,插件卸载时会自动移除,不会残留。
实现方式:为什么是「一个样式表」而不是「一个组件」
左侧栏的外壳(品牌行、新会话按钮、折叠行为)由官方包 @deepseek-ai/dsh-client-ui-sidebar 渲染。
DSH 的槽位系统里有两条硬规则(已实测):
- 声明即认领:只有声明了某个子槽的注册者才能渲染它;
- 遮蔽者不能重复声明别人的子槽(会抛
slot "..." is already declared)。
所以想「改外壳」只有两条路:
- 接管整个
sidebar座位 → 会连同它声明的 7 个子座位一起失效(会话树、设置行、插件入口……全都要自己重写),除非先把官方外壳从组合里禁用掉,再自己声明同一套座位。 - 只加样式 → 外壳、座位、占用者全部保持原样,只是视觉上隐藏品牌行、并把「新会话」按钮重画一遍。
本插件整体上是第二条:样式表打底,零构建,只在自己真正需要行为的地方才碰槽位。 13 条规则全是纯 CSS,最坏情况只是「选择器失效 → 品牌行回来了、新会话按钮变回官方那张卡片」, 永远不会把侧边栏弄坏。
只有一处例外 —— 规则 14 的设置入口是真实的组件:它要的不只是「看起来像一个入口」,
而是「点它直接开设置,而不是弹账号菜单」,还要和旁边的账号行分成两个热区。
伪元素做不到这两件事(它只能继承所在按钮的行为),所以那里注册了一个真正的
`` 到官方外壳的 sidebar.footer.action 座位,由 CSS 排到设置行右端
(见 规则 14)。这一段是本插件唯一的 JS 逻辑。
选择器为什么这么写
DSH 的 class 名是 CSS Modules 哈希(_3WPZCG_logoRow),每次构建都会变,不能用来写皮肤。
这里只用两种跨版本稳定的锚点:
/* 1. 顶部品牌行:只在「渲染了展开态品牌标识」时命中 */
[data-slot="sidebar"] > div > div[data-window-drag]:has([data-slot="sidebar.brand.name"]) {
display: none !important;
}
/* 2. 新会话按钮:sidebar 根容器唯一的直接子 ,
保留但改画成 nav 里 .panelRow 的同款(见下) */
[data-slot="sidebar"] > div > button {
height: 32px;
min-height: 32px;
margin: 0 0 4px; /* 左右 0 与面板行同边距;4px = 面板行行距 */
padding: 5px 8px;
border: none;
border-radius: var(--dsw-radius-md);
background: transparent !important;
color: var(--dsw-alias-label-primary);
font-weight: 400;
}
[data-slot="sidebar"] > div > button:hover {
background: var(--dsw-alias-interactive-bg-hover) !important;
}
[data-slot="sidebar"] > div > button:focus-visible {
outline: var(--dsw-focus-ring-width) solid var(--dsw-focus-ring-color, var(--dsw-alias-state-business-primary));
outline-offset: -2px;
}
/* 内容左对齐 + 图标 16px::has(> span) 只在宽态成立(收起态不渲染文字 span) */
[data-slot="sidebar"] > div > button > span:first-child > span:has(> span) {
justify-content: flex-start;
width: auto;
gap: 8px;
}
[data-slot="sidebar"] > div > button > span:first-child > span:has(> span) > svg {
width: 16px;
height: 16px;
}
/* 2b. 折叠开关(面板图标):展开态也钉到官方浮层的落点(红绿灯右侧)。
全屏必须排除 —— 那时没有红绿灯,浮层与 topStrip 本来就都在 left:12px。 */
html[data-platform="darwin"]:not([data-fullscreen]) [data-slot="sidebar"] > div > :first-child {
--dsh-sidebar-toggle-left: 88px; /* ← 与官方 .leadingSeat 的 left 同值;上游若改要同步 */
justify-content: flex-start;
padding-left: var(--dsh-sidebar-toggle-left);
}
/* 3. 全局面板行(插件 / 自动化任务 / …):pill 与列表 pill 同边距 */
[data-slot="sidebar"] > div > nav > button {
margin-left: 0;
margin-right: 0;
gap: 8px;
}
/* 4. 工作区行(DSH UI Lab / Pico / …) */
[data-slot="sidebar"] [data-row-key^="workspace:"] {
gap: 8px;
}
/* 5. 会话行:官方这里不是 flex gap(行 gap:0 + 标题 margin-left:4px),
所以改标题自己的左外边距;标题恒为行的第 2 个子元素 */
[data-slot="sidebar"] [data-row-key^="session:"] > span:nth-child(2) {
margin-left: 8px;
}
/* 6. 整体左右内边距 12px → 8px(一处决定三件事,见下) */
[data-slot="sidebar"] > div {
--dsh-sidebar-inline-padding: 8px;
}
/* 7. 「展开其余 N 个会话」按钮:与上方会话行同款
—— 高 32px(规则 9 统一)/ 14px 字 / 圆角 12px / hover 同款底色 / 文字起点 40px
—— 文案:隐藏官方文字,用 ::after 显示,aria-expanded 区分两态 */
[data-slot="sidebar"] button[data-row-key^="overflow:"] {
margin-top: 2px;
padding-left: calc(32px + var(--dsh-workspace-indent, 0px));
border-radius: var(--dsw-radius-md);
font-size: 0;
}
[data-slot="sidebar"] button[data-row-key^="overflow:"]::after {
content: "更多会话";
font-size: 14px;
}
[data-slot="sidebar"] button[data-row-key^="overflow:"][aria-expanded="true"]::after {
content: "收起";
}
[data-slot="sidebar"] button[data-row-key^="overflow:"]:hover {
background: var(--dsw-alias-interactive-bg-hover);
}
/* 8. 「工作区」区段标题:左内边距 4px → 8px,让标题与下方图标同一条 16px 垂线;
收起态复原官方值(轨道里只剩图标按钮,不能推右 8px) */
[data-slot="sidebar.workspaces"] > div > :first-child {
padding-left: 8px;
}
[data-sidebar-collapsed] [data-slot="sidebar.workspaces"] > div > :first-child {
padding-left: 0;
}
/* 12. 去掉侧栏的渐变染色,只保留半透明基色(逐态复刻官方的基色算法,
不透明度取规则 10 的旋钮;含 prefers-reduced-transparency 分支,
避免顶掉无障碍偏好) */
[data-platform="darwin"] div:has(> [data-slot="sidebar"]) {
background: color-mix(in srgb, color-mix(in srgb, var(--dsw-specific-sidebar-fill) 97%, #7a9bf0) var(--dsh-sidebar-alpha-light), transparent);
}
[data-platform="darwin"] [data-ds-dark-theme] div:has(> [data-slot="sidebar"]) {
background: color-mix(in srgb, var(--dsw-specific-sidebar-fill) var(--dsh-sidebar-alpha-dark), transparent);
}
@media (prefers-reduced-transparency: reduce) {
[data-platform="darwin"] div:has(> [data-slot="sidebar"]) {
background: color-mix(in srgb, var(--dsw-specific-sidebar-fill) 90%, transparent);
}
}
/* 11. 激活工作区的文件夹图标:去掉蓝色强调,与文字同色 */
[data-slot="sidebar"] [class*="folderActive"] {
color: inherit;
}
/* 13. 无状态(idle)的会话行:左侧 16px 槽位补一个灰点
—— 只在座位锚点存在且为空时命中(= 官方判定为 idle 的那一类行)
—— 6px 可见圆 = 官方彩色实心点(10px 盒 / ::after{inset:20%})的同一尺寸 */
[data-slot="sidebar"] [data-row-key^="session:"] > span:has(> [data-slot="sidebar.session.row.leading"]:empty)::after {
content: "";
flex: none;
width: 6px;
height: 6px;
border-radius: 50%;
background: var(--dsw-alias-state-idle-primary);
}
/* 15. 工作区与工作区之间:4px → 8px
—— 官方只用一个类的类名分组(_7514NG_groupSection),所以用后缀匹配;
选择器带三个属性段,压过官方那条两类的规则,不需要 !important */
[data-slot="sidebar"] [class*="groupSection"] + [class*="groupSection"] {
margin-top: 8px;
}
/* 10. 侧边栏底色旋钮:一态两个(基色 + 不透明度),想微调只动这四行 */
div:has(> [data-slot="sidebar"]) {
--dsh-sidebar-fill-dark: #151517; /* 暗色基色 = 对话区 --dsw-alias-bg-base(官方原值 #1b1b1c) */
--dsh-sidebar-fill-light: #ffffff; /* 亮色基色 = 对话区 --dsw-alias-bg-base(官方原值 #f9fafb) */
--dsh-sidebar-alpha-dark: 50%; /* 暗色不透明度(官方值) */
--dsh-sidebar-alpha-light: 90%; /* 亮色不透明度(官方 40%;提到 90% 才压得住窗口材质) */
--dsw-specific-sidebar-fill: var(--dsh-sidebar-fill-light);
}
body[data-ds-dark-theme] div:has(> [data-slot="sidebar"]) {
--dsw-specific-sidebar-fill: var(--dsh-sidebar-fill-dark);
}
/* 9. 行高统一为 32px(面板行 / 新会话行 / 区段标题行 / 工作区行 / 会话行 / 更多会话) */
[data-slot="sidebar"] [data-row-key^="workspace:"],
[data-slot="sidebar"] [data-row-key^="session:"],
[data-slot="sidebar"] button[data-row-key^="overflow:"],
[data-slot="sidebar.workspaces"] > div > :first-child {
height: 32px;
}
/* 面板行与新会话行官方是靠 min-height:36px + padding:7px 8px 撑出来的(行高 22px),
上下内边距收到 5px 才是 22 + 5 + 5 = 32px */
[data-slot="sidebar"] > div > nav > button,
[data-slot="sidebar"] > div > button {
min-height: 32px;
height: 32px;
padding-top: 5px;
padding-bottom: 5px;
}
/* 14. 设置行右侧的设置入口:一个真实按钮(注册在 sidebar.footer.action 座位里)。
脚区从「竖排两行」改成「一行两列」,设置行占左列、footerActions 占右列,
两个热区因此不重叠;按钮 28×28 与「新建工作区」按钮同款,齿轮用遮罩画。 */
div:has(> [data-slot="sidebar"]) [data-slot="sidebar"] > div > div:has(> div > [data-slot="sidebar.settings"]) {
display: grid;
grid-template-columns: minmax(0, 1fr) auto;
align-items: center;
column-gap: 4px;
}
div:has(> [data-slot="sidebar"]) [data-slot="sidebar"] > div > div:has(> div > [data-slot="sidebar.settings"]) > :first-child {
grid-area: 1 / 2; /* footerActions:设置入口 */
}
div:has(> [data-slot="sidebar"]) [data-slot="sidebar"] > div > div:has(> div > [data-slot="sidebar.settings"]) > :last-child {
grid-area: 1 / 1; /* settingsArea:账号行 */
}
.dsh-settings-entry {
width: 28px;
height: 28px;
padding: 0;
border: none;
border-radius: var(--dsw-radius-sm);
background: transparent;
color: var(--dsw-alias-label-secondary);
cursor: pointer;
position: relative;
}
.dsh-settings-entry::after {
content: "";
position: absolute;
inset: 6px;
background-color: currentColor;
mask: var(--dsh-settings-gear) center / 16px 16px no-repeat;
}
.dsh-settings-entry:hover { background: var(--dsw-alias-interactive-bg-hover); }
/* 收起轨道:脚区复位成官方的竖排,入口不显示 */
[data-sidebar-collapsed] div:has(> [data-slot="sidebar"]) [data-slot="sidebar"] > div > div:has(> div > [data-slot="sidebar.settings"]) {
display: flex;
flex-direction: column;
align-items: center;
column-gap: 0;
}
[data-sidebar-collapsed] .dsh-settings-entry { display: none; }
这几条规则各修了什么:
-
规则 2b — 折叠开关(面板图标)固定到红绿灯右侧:这是本次新增的一条,也是唯一 一条改变展开态布局位置的规则。
官方的开关在 macOS 桌面端有两个落点:展开时由侧栏自己的
topStrip承载,官方给它justify-content: flex-end,于是被推到侧栏最右边;收起时侧栏整列宽度归 0 (AppFrame里collapsedWidth = darwin ? 0 : 56—— macOS 上「收起 = 整列隐藏,连轨道都没有」), 开关改由侧栏之外的官方浮层接管:HeaderLeadingControls渲染在.leadingSeat{position:absolute; top:11px; left:88px}里,落在红绿灯右侧。同一个按钮、两个落点,展开/收起时会横向跳 152px。这条规则把展开态也钉到浮层那一格:
官方展开态 官方折叠态(基准) 现在(两态) 按钮 x 240..268(侧栏最右) 88..116(红绿灯右侧) 88..116 按钮 y 11..39 11..39 11..39 实测图标中心 (253.75, 24.75) (101.75, 24.75) (101.75, 24.75) 垂直方向本来就相等,所以只动横向:主轴改成
flex-start,左内边距取 88px 旋钮。88px与官方.leadingSeat的left是同一个数(上游若改要同步);顶部top:11px对得上是因为topStrip高 52px、下内边距 2px、align-items: center天然给出 y = 11..39。

这张图是真实窗口截图(
screencapture -l,2x),不是 DOM 副本 —— 三行分别是 「关掉本规则」「开着本规则」「侧栏收起(基准)」,三态在同一台机器、同一次会话里连拍。 逐帧验证:连拍 40 帧(约 90ms 一帧),期间状态来回切换了两次(展开 → 收起 → 展开), 图标包围盒恒为 x 190..217 / y 36..63@2x(= CSS x 95..108.5 / y 18..31.5), 过场帧与静止帧的像素个数也完全相同(244)—— 没有位移、没有闪烁。
必须排除全屏(html:not([data-fullscreen])):全屏下没有红绿灯,官方把浮层挪到
left:12px、topStrip 也改成 flex-start,开关在两态本来就都落在 x = 12..40,
不排除反而会被这条规则推到 88px。
选择器用「sidebar 根容器的第一个子元素」定位 topStrip:它只在 darwinDesktop 下渲染,
而 isDarwinDesktop() 就是读 [data-platform="darwin"](同一个属性),两者同义,
所以 Web 端永远不会命中这条(那里第一个子元素是品牌行)。
-
规则 2 — 新会话按钮:保留,但画成列表行:「新会话」是外壳自己渲染的按钮 (
SidebarRoot里sidebar根容器唯一的直接子 ``),官方把它做成一张独立卡片:38px高、.5px描边、elevated 半透明底、内容居中、下外边距12px; 而紧挨着它的nav.panelList面板行是32px无底色胶囊、图标与文字左对齐。 品牌行(规则 1)去掉后两者上下相邻 —— 一张卡片压在一份列表上,看起来是两种东西。规则 2 把它改画成面板行的同款,实测(真实 Chrome,
tools/verify-new-session.mjs):官方 .newSession.panelRow(nav)本插件 高度 38px 32px 32px(规则 9 统一) 左右外边距 14px( margin: 0 2px+ 12px 内边距)8px 8px 到下一行的间距 12px 4px 4px 描边 / 底色 .5px描边 + elevated 半透明底无 / transparent 无 / transparent 内容对齐 居中(图标 109..123、文字 129) 左对齐 左对齐 图标 14px 16px 16px(都落在 16px 垂线) 图标→文字 6px 8px 8px 文字 x 129px 40px 40px 字重 500 400(继承根) 400 hover --dsw-alias-button-floating-hover(卡片更亮)--dsw-alias-interactive-bg-hover列表行同款 几个不显然的地方:
- 为什么下外边距是 4px:它就是
nav.panelList的行间距。设成 4px 后,「新会话」 与面板行之间、面板行彼此之间的间距完全一样,读起来是同一份列表(否则会多出 8px 的断口,又变回「一个按钮 + 一份列表」)。 - 为什么底色要用
!important:官方在 macOS 上给这张卡片叠了四层底色 ([data-platform=darwin] .newSession亮/暗两态 + 各自的 hover),选择器都是 2~4 层,普通规则压不过。作用域只有这一个按钮,而且展开态与收起态要的都是 「无底色 + hover 用interactive-bg-hover」,所以收起态不需要再写复位。 - 为什么内容对齐用
:has(> span)守卫:官方把内容做成.newSessionContent{justify-content:center; width:100cqw},要改成左对齐就得改它; 而文字 span 只在宽态渲染,于是button > span:first-child > span:has(> span)恰好等于「这一列是展开的」。收起态的 56px 轨道(以及 Windows 的 36×36 圆形按钮) 自动不命中,轨道里的图标仍然是官方值(18px、居中)—— 已由tools/verify-new-session.mjs断言(:has()守卫一旦失效,这条断言会红)。 - ⌘N 键帽保留:官方的
ShortcutKeys(12px /label-tertiary)只在 hover 显示, 静止态与列表行完全一样;宽态下 Tooltip 是关掉的,删掉它就再没有快捷键提示了。 margin-left/right: 0与规则 3 同源:面板行被规则 3 归零了margin: 0 2px, 两边的 pill 左边缘因此都落在规则 6 的 8px 内边距上。
- 为什么下外边距是 4px:它就是

上面那张是 DOM 副本(真实产物 CSS + 真实外壳 JSX)。下面这张是真实窗口截图 (
screencapture -l,2x,亮色外观)。对它做像素扫描:五行的文字左边缘都在 2x 图的 第 81/82 像素(= CSS 40.5/41px,多出的 0.5~1px 是字形自身的左留白), 行间距也一律 40px —— 与面板行完全同一条线、同一个节奏。

-
规则 3 — 面板 pill 比列表 pill 多缩 2px:官方给面板行写了
margin: 0 2px, 而列表行没有。归零后两类 pill 的左右边距相等(绝对值由规则 5 决定), 图标也随之内缩对齐。 -
规则 3/4/5 — 文字落在三条不同的线上:面板行
gap: 8px→ 46px、工作区行gap: 6px→ 42px、 会话行margin-left: 4px→ 40px。三者统一到 8px 后,文字自然同线(40px) (规则 2 把「新会话」也一并拉上这条线 —— 它官方是居中的,没有自己的左对齐线)。 会话行之所以单独用margin-left而不是gap:给它加gap会把标题与时间戳之间也一起撑开。 -
规则 6 — 收紧整体内边距:官方把
--dsh-sidebar-inline-padding: 12px写在根元素自己身上, 所以必须命中同一个元素才能覆盖([data-slot]属性的特异性高于单个 class)。 它一处决定:- 列表行 pill 的左右外边距(12px → 8px)
- 面板行 pill 的左右外边距(同为 12px → 8px)
- 工作区的
edge-inset—— 也就是右侧「padding +scrollbar-gutter预留 + margin」那套对称算法
图标随之外移:20px →