CSS变量无法实现遮罩层动态高度,因其不感知DOM尺寸变化,必须由JS测量后注入变量,CSS仅消费该值;核心是JS完成测量与注入,CSS负责渲染。

遮罩层高度要随内容或容器实时变化,必须靠 JS 测量后注入变量,CSS 仅负责消费它。
为什么 CSS 变量不能自己算出高度
CSS 是声明式语言,var(--height) 只是文本替换,不会触发 layout 或调用 getBoundingClientRect()。即使你写了 height: var(--height);,这个 --height 也得先由 JS 算好、设好,否则就是无效值(比如 height: var(--height, auto) 会 fallback 到 auto)。
- 常见错误:在 :root 里写
--height: 100vh;,以为能响应视口缩放——其实只是初始值,窗口 resize 后不会自动更新 -
min-height: max-content或fit-content不等于“把真实高度赋给变量”,它们只影响布局,不产出可复用的数值 - 伪元素
::before也无法用content: attr(data-height)拿到 JS 写入的 height 值,因为 attr() 只读 HTML 属性,不读 style 或自定义属性
JS + CSS 变量联动的最小可行方案
核心动作就两步:测量 → 注入。关键不是“怎么写 CSS”,而是“什么时候测、测什么”。
- 测
getBoundingClientRect().height,不是offsetHeight:前者含 border/padding/滚动条可见区域,后者在 display: none 元素上返回 0 - 注入目标选元素自身,而非 :root:避免全局污染,也方便组件级复用,例如
el.style.setProperty('--mask-height', h + 'px') - 监听时机:DOMContentLoaded 后测一次;若内容异步加载(如图片、API 数据),需等
img.onload或Promise.all()完成后再测;resize 时建议节流(requestAnimationFrame或 60ms throttle) - CSS 中直接用:
height: var(--mask-height);,无需 calc() 包裹——变量已是带单位的合法长度值
容易被忽略的兼容与性能点
看似简单,但实际项目里最容易在这里翻车:
立即学习“前端免费学习笔记(深入)”;
- 遮罩层父容器如果用了
transform、will-change或contain: layout,可能让getBoundingClientRect()返回的坐标/尺寸失真,务必在无干扰环境下测 - SSR 渲染时 JS 还没执行,变量为空,需预设 fallback:
height: var(--mask-height, 0);或配合@supports (height: var(--x))做样式降级 - 频繁触发测量(比如 scroll 事件里直接测)会导致 layout thrashing,哪怕只测一个元素,也建议缓存结果并加 dirty flag 判断是否真需要重测
- 移动端 WebView(尤其旧版 Android UC)对
style.setProperty()支持不稳定,可降级为el.setAttribute('style', `--mask-height: ${h}px`)


















