浮层按打开顺序取号与吸顶分割边界
不靠写死的大数字排先后:TuffEx 的浮层从同一个计数器按打开顺序取 z-index,抽屉先把计数抬到 10000;吸顶条用 1px 细线而非投影。
浮层按打开顺序取号与吸顶分割边界
在专业桌面端应用中,随意堆砌 z-index 会导致严重的视图穿透与遮挡冲突。TuffEx 不给浮层分固定的层级档位,而是让它们按打开顺序,从同一个计数器取号。
消除 z-index 军备竞赛
传统前端工程遇到图层遮挡时,往往随意写下 z-index: 9999 或 99999。这会导致:
- 下拉菜单穿透系统弹窗。
- 气泡提示被吸顶栏截断。
- 多 Agent 协同编写业务模块时层级彻底失控。
固定的层级档位也解决不了这个问题:弹窗里打开的下拉菜单必须盖住弹窗,抽屉里打开的弹窗又必须盖住抽屉。谁该在上面,取决于打开的先后,而不是组件的种类。
按打开顺序取号
TuffEx 的浮层在打开时向 z-index 分配器取下一个号(next(),即当前值加 1),所以后打开的总是盖在先打开的上面:
- 取号的组件:TxModal;基于 TxBaseAnchor 的浮层,如 TxPopover、TxTooltip、TxSelect、TxDropdownMenu、TxContextMenu;以及 TxCommandPalette、TxFlipOverlay、TxPicker、TxLoadingOverlay 和各类 Dialog。TxToastHost 在每次调用
toast()时取号。 - 起点:计数器从 2000 起步(
DEFAULT_Z_INDEX_SEED),第一个浮层拿到 2001。不带参数调用refresh()时,会改读 CSS 变量--tx-index-popper,取两者中较大的那个。 - 抽屉:TxDrawer 打开时先
refresh(10000),把计数抬到至少 10000 再取号,所以第一个抽屉是 10001,在抽屉里打开的浮层从 10002 往上排。传了z-index时直接用这个值,并把计数抬到至少这个值。 - 只增不减:关闭浮层不会退号,下一个浮层照样取更大的号。
- 按应用隔离:
app.use(Tuffex)时为这个应用建一个分配器,没有 Vue 应用的调用方共用模块级的那一个。
业务代码要做自己的浮层时,同样用 useZIndexAllocator() 取号,不要写死数字。
variables.scss 里另有 --tx-index-normal: 1、--tx-index-top: 1000、--tx-index-popper: 2000 三个令牌。--tx-index-popper 除了作分配器的起点,也是 TxVersionCapsule 面板的层级;--tx-index-top 给 TxMotion 的全局进度条用,让它压在所有浮层之下;--tx-index-normal 组件没有用到。TxMotion 的全局指针层是例外,固定为 2147483647:它要跟着指针盖过抽屉和对话框,而分配器的号没有上限。组件内部写死的 z-index 大多是 −1 到 10 的小数值,只在组件自己的层叠上下文里排先后。
吸顶条使用 1px 细线而非投影
当表格表头或操作条固定在顶部、下方内容滚动经过时,禁止使用弥散投影(Drop Shadow)作为分割。
// 错误写法:阴影让吸顶条漂浮在半空,破坏了滚入内容首行的清晰度
.sticky-bar { box-shadow: 0 4px 12px rgba(0,0,0,0.15); }
// 正确写法:使用 1px 细线形成清脆物理截断
.sticky-bar {
border-bottom: 1px solid var(--tx-border-color);
background-color: var(--tx-bg-color); // 必须是不透明实底
}
吸顶元素是视窗的物理闸门,而非空中悬浮物。1px 细线能明确界定滚出边界,保持整体版面的严谨秩序。