CSS无块级局部变量,自定义属性(--foo)必须显式声明在选择器内;写.card { --w: 16; }仅对该元素生效,子元素不继承,需挂载到DOM节点或用data属性+calc()实现真局部控制。

CSS 本身没有“局部变量”概念,所谓“局部”只能靠作用域限定(如 class、data 属性)配合 var() 实现,不能像 JS 那样声明块级作用域变量。
为什么不能直接在元素上定义 :local CSS 变量
CSS 不支持 :local 这类伪类或关键字;所有自定义属性(--foo)都必须显式声明在某个选择器作用域内。常见误操作是把变量写在组件 class 内部却期望它自动“局部生效”,结果发现子元素没继承、或被父级同名变量覆盖。
- 变量必须挂载到具体 DOM 节点(如
.card元素),用style="--aspect-w: 16; --aspect-h: 9;"才算真正“局部” - 仅写
.card { --aspect-w: 16; }是无效的——它只对.card自身生效,其子元素不会自动获得该变量,除非你额外加.card * { line-height: inherit; }类似的继承兜底(但aspect-ratio不继承) - 若用
scoped(如 Vue SFC),.card { --aspect-w: 16; }会被编译成带属性选择器的规则,但aspect-ratio: var(--aspect-w) / var(--aspect-h)若写在子元素上,仍需确保变量已注入到该子元素节点或其祖先
用 data 属性 + calc() 实现真·局部宽高比
最可控的方式是把比例信息存在 data- 属性里,再用 calc() 在样式中读取。浏览器原生支持 attr() 仅限于 content 属性,所以得靠 JS 注入或预设 CSS 规则。
- HTML 中写:
- CSS 中用预设规则匹配常见比例:
.media[data-ratio="16/9"] { aspect-ratio: 16 / 9; } .media[data-ratio="4/3"] { aspect-ratio: 4 / 3; } .media[data-ratio="1/1"] { aspect-ratio: 1; } - 需要动态时,JS 注入 style:
el.style.setProperty('--ratio', '16/9');,再配合aspect-ratio: var(--ratio);——但注意 Safari 16.4+ 才支持var()用于aspect-ratio的值(旧版会忽略)
@supports 降级到 padding-top 方案
当目标环境不支持 aspect-ratio 或 var() 动态值时,必须回退到传统 padding hack,且不能依赖全局变量计算。
- 直接在元素上写内联 style:
style="padding-top: calc(var(--aspect-h) / var(--aspect-w) * 100%);"是无效的——calc()里的var()在 padding 中不被解析 - 正确降级方式:用 JS 算好百分比后写死,或用 SCSS 函数预编译:
$ratio: percentage($h / $w);→padding-top: #{$ratio}; - 必须包裹
@supports not (aspect-ratio: 1) {},否则新旧规则同时生效会导致布局错乱
真正难的不是怎么写 var(--w) / var(--h),而是判断何时该放弃变量、改用 data- 属性硬编码比例——尤其当组件要 SSR 渲染或兼容 IE11 时,CSS 变量根本不可用。
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!











