8.5 KiB
2026-09-16 工作日志
UI 控件横向内边距拆分(输入型 vs 点击型)
背景:--fms-control-padding-x 原本被 6 处共用,输入框偏宽。
改动:
src/theme/tokens.css新增--fms-field-padding-x: 4px(输入型控件专用),--fms-control-padding-x: 10px保留给按钮/标签页等「点击型」元素。- 切到
--fms-field-padding-x的 4 处:ui/input/index.scss(.input-wrapper单行 +.input-textarea多行)、ui/select/index.scss(触发器)、ui/date/index.scss(.fms-date-trigger/.fms-range-trigger共用规则,DatePicker + RangePicker 都覆盖)。 - 保持 10px:
ui/button/index.scss:13、ui/tabs/index.scss:147。
结论:以后调输入框内边距只动 --fms-field-padding-x,不会波及按钮/标签页。
DatePicker 触发器布局重构(清除按钮绝对定位)
问题:.fms-date-suffix 这个 <span> 没有 v-if,空态也占位;外层 gap: 6px 照常生效,
所以 input 右侧总有距离。更糟的是 hover 时清除按钮从 display:none 变 inline-flex,
会挤压 input 造成文字左右跳动。
改法(ui/date/index.scss):
.fms-date-trigger/.fms-range-trigger:加position: relative,删掉gap: 6px。.fms-date-suffix:改position: absolute+top/right/bottom: 0,脱离文档流;pointer-events: none,子元素> *恢复auto(避免绝对定位层挡住触发器点击)。.fms-date-input/.fms-range-input:padding: 0(原生元素不留内边距)。
第二版修正(重要):第一版给 input 加了 padding-right: 18px 预留清除按钮位,
导致无值时右侧恒有 18px 空白。改为对齐 antd 的「叠放 + 透明淡入」:
.fms-date-clear {
display: inline-flex; /* 常驻 DOM,不再 display:none */
opacity: 0; /* 默认透明 */
pointer-events: none;
transition: opacity var(--fms-duration-base) var(--fms-ease-standard);
}
.fms-date-trigger:is(:hover, :focus-within) .fms-date-clear,
.fms-range-trigger:is(:hover, :focus-within) .fms-date-clear {
opacity: 1; pointer-events: auto;
}
组件库通行做法(查证结论,别再自己发明)
| Ant Design | Element Plus | |
|---|---|---|
| 按钮定位 | absolute |
absolute |
| 隐藏方式 | visibility:hidden(Input)/ opacity:0(Picker) |
条件渲染 |
| 是否预留空间 | 不预留,靠叠放/淡入淡出 | 常驻预留(clearable 时 padding+14px,被吐槽) |
| 切换动画 | 有(opacity 过渡) | 无 |
- antd Input 用
visibility: hidden而非display:none,因为前者保留布局空间,文字不跳。 - antd DatePicker 的
-clear与-suffix叠在同一位置,hover 时 clear 淡入、suffix 淡出。 - antd 原生
input一律padding: 0,内边距全由外层 wrapper 提供。 - 结论:正确解法是「绝对定位 + opacity 过渡」,不是「预留 padding」。后者必然造成常驻空白。
实测验证(Playwright 量取真实渲染几何):
- 未 hover:input
padding: 0/0,触发器 296px 内 input 286px,Lgap 5 / Rgap 5,clearopacity:0。 - hover 后:input 宽度漂移 0.00px、leftGap 漂移 0.00px,clear
opacity:1。 - 即:空间不浪费 + 文字不跳动,两个目标同时达成。
复用经验:本地用 Playwright 验证前端视觉
本项目 fms-vue 没装 playwright;用托管 workspace 的:
- 安装:
C:/Users/Administrator/.workbuddy-ai/binaries/node/versions/22.22.2-2/npm.cmd install playwright(在C:/Users/Administrator/.workbuddy-ai/binaries/node/workspace) - 运行:
"C:/Users/Administrator/.workbuddy-ai/binaries/node/versions/22.22.2-2/node.exe" script.mjs - 坑:ESM 不支持
NODE_PATH,也不支持裸目录绝对路径,必须写import { chromium } from 'file:///C:/.../node_modules/playwright/index.mjs'。 /demo组件演示页需要登录态。绕过登录:后端POST /api/auth/login({"orgid":"G3HD","userid":"g3soft","password":"g3soft"})拿 token, 用addInitScript写入sessionStorage['fms-login'](形如{loginInfo:{token,user}})localStorage['fms-user']({userInfo:{orgId,account}}),再进/demo。
- 左侧分类要点击「DatePicker 日期选择」才会渲染对应 demo,直接 goto 拿到 0 个触发器。
- 验证完记得删掉临时脚本和截图。
侧栏改为黑色(深色导航面 + 对比度重配)
需求:fms-layout 侧栏背景改黑,字体与图标颜色要跟着调(否则黑底上看不见)。
关键决策:新增侧栏专用 token,不动全局中性色。
浅色主题下侧栏要黑,但 --fms-surface / --fms-text 是顶栏、内容卡、全部业务页面
共用的浅底配色;直接改全局会让整个主区一起变深。故在 src/theme/tokens.css 的
:root 与 .dark 各加一组 --fms-sidebar-*,只被 AppSidebar.vue / NavMenuItem.vue 引用:
| token | 浅色 | 深色 |
|---|---|---|
--fms-sidebar-bg |
#111318 |
#0b0d11 |
--fms-sidebar-text |
#d7dbe2 |
#ced3db |
--fms-sidebar-text-secondary |
#8b93a2 |
#838b99 |
--fms-sidebar-hover-bg |
rgba(255,255,255,.08) |
.1 |
--fms-sidebar-divider |
rgba(255,255,255,.12) |
.14 |
--fms-sidebar-accent-fill |
color-mix(primary 38%, #000) |
46% |
--fms-sidebar-accent-edge |
color-mix(primary 40%, #fff) |
46% |
--fms-sidebar-logo-bg |
color-mix(primary 55%, #fff) |
45% |
踩坑点(下次改深色底必看):默认主色「墨蓝」#0f172b 本身就是近黑。
原激活态写法 color: var(--fms-primary) + background: color-mix(primary 10%, transparent)
在黑侧栏上等于完全不可见。
已改文件:
src/theme/tokens.css— 新增上述两组变量。src/layouts/components/AppSidebar.vue— 底色/文字/hover/focus/次级文字/滚动条换成--fms-sidebar-*;去掉box-shadow: var(--fms-shadow-right)(阴影落黑底不可见, 反在交界处糊灰边),改border-right: 1px solid var(--fms-sidebar-divider); Logo 底改--fms-sidebar-logo-bg+ 图标#111318。 团队下拉菜单(.fms-team-menu-*)保持浅色 token 不变 —— 它在body下(Teleport)。src/layouts/components/NavMenuItem.vue— 全部--fms-text/--fms-secondary/--fms-border换--fms-sidebar-*;hover 文字提到#fff;激活态见下节。src/layouts/DefaultLayout.vue— 侧栏侧分隔条::before提亮 (--fms-sidebar-text-secondary),否则浅色下拖拽线在黑底上看不见。
对比度(底 #111318):菜单文字 12.7:1、次级文字/箭头 5.9:1、Logo 图标 7.2:1。
菜单选中项:主题色实底 + 白字 + 主色亮描边
需求:选中菜单项用主题色做背景、文字白色。
走过的弯路(重要,别再试):第一版按常规模板写成
「background: color-mix(primary 42%, #fff) + color: #fff」(即把主色提亮当浅色底)。
实测白字对比度只有 1.4~2.7:1,全部不合格且远低于 AA 的 4.5:1 ——
因为任何主色与白混到能看清色相的亮度,都已经是浅色(pastel),白字压不住。
结论:黑侧栏上的选中块必须是「深底 + 白字」,不能用「浅底 + 深字」。 方案是把主题色拆成一对 token:
--fms-sidebar-accent-fill=color-mix(primary 38%, #000)—— 压暗保留色相, 作为实底,白字对比度 5.1~19.2:1 全部达标(最深/最浅预设都过)。--fms-sidebar-accent-edge=color-mix(primary 40%, #fff)—— 提亮做主色描边。 没有它,近黑主色(墨蓝)的实底与侧栏底只有 1.04:1,选中态整块消失; 有描边后边界可辨度 3.96:1。
即:文字可读性靠填充、选中可辨识性靠描边,二者分离,这样 9 个预设色全过。
提亮版仍用于 focus 描边(NavMenuItem / AppSidebar 的 :focus-visible)。
连带细节:加了 border: 1px 会挤占尺寸导致选中时文案左右跳动,
故 .fms-nav-link 的 padding 由 0 8px 收为 0 7px 补偿(折叠态规则在后、特异性更高,
padding: 0 不受影响)。激活项 hover 只轻微提亮填充,不退回普通 hover 的半透明白底。
验证:pnpm lint 无新增问题(唯一 error 是既有 createCellRenderer.old.js 的
no-unused-vars,与本改动无关);pnpm build --outDir dist-verify --emptyOutDir 通过。