共计 3582 个字符,预计需要花费 9 分钟才能阅读完成。
CSS 变量的作用域是什么?
变量作用域,变量的可用性范畴。变量并不总是无效可用的,而限定变量的可用性范畴就是变量的作用域。而 CSS 变量在 CSS 层次结构中申明的地位,决定了它在整个层次结构中的可用性范畴。
通常来说,CSS 变量仅对申明它的元素的子元素可见。比方上面的例子中,--bgColor
变量对 child 元素可见:
<div class="parent">
parent
<div class="child">child</div>
</div>
.parent {--bgColor: pink;}
.child {background: var(--bgColor);
}
但如果反过来则不可见:
.child {--bgColor: pink;}
.parent {background: var(--bgColor);
}
作用域类型
CSS 变量遵循词法作用域(动态作用域)规定,有两种作用域类型——全局作用域 和部分作用域。
全局作用域
在 :root
中申明的 CSS 变量即全局作用域的变量,即能够在 CSSOM 中任意地位应用。
/* 定义全局变量 */
:root{--primary-color: pink;}
/* 任意地位都能够拜访全局变量 */
.wrapper{background: var(--primary-color);
}
部分作用域
而在其余 CSS 层级中申明的变量仅对该 CSS 层级以及它的子级可见。
<div class="parent text">
parent
<div class="child text">child</div>
</div>
.parent {
--fontSize: 24px;
--lineHeight: 1.8;
}
.child {
--fontSize: 18px;
--lineHeight: 1.6;
}
.text {font-size: var(--fontSize);
line-height: var(--lineHeight);
}
在上面对例子中,能够用雷同的命名在不同的 CSS 块中申明和拜访变量。
部分作用域总是能够拜访外层作用域或者全局作用域的变量,相同则不可。
变量晋升
和 JavaScript 一样,CSS 变量生命能够被 晋升,即 CSS 变量能够再申明之前应用他们。在浏览器渲染相应的 HTML 元素款式前,会将 CSS 变量的申明晋升并挪动到 CSSOM 的最顶部。
body {background-color: var(--bgColor);
}
:root {--bgColor: pink;}
body {background-color: var(--bgColor);
}
:root {--bgColor: pink;}
如下面的例子中,CSS 变量 --bgColor
能够在:root
伪类选择器申明之前应用。CSS 变量能够先拜访再申明这一个性,使得 CSS 变量成为一个十分弱小的性能点。
变量默认值
如上面的例子中,被逗号分隔后的第二个值 1.2 为默认值,即如果 --scale
未被赋值则应用 1.2 这个数值。
.bigger {transform: scale(var(--scale, 1.2));
}
当应用 var()
函数时,能够调配一个或多个回退的属性值(应用逗号分隔),比方设置字体:
html {font-family: var(--fonts, Helvetica, Arial, sans-serif);
}
还能够应用一连串的变量回退,但须要应用 var()
嵌套起来:
.bigger {transform: scale(var(--scale, var(--secondFallbackScale, 1.2));
}
如果 --scale
未被定义,会尝试下一个值即 --secondFallbackScale
。如果--secondFallbackScale
也未被定义,最终会回退到 1.2。
模块化
CSS 变量的弱小之处在于,作用域 的个性有助于设计一个代码整洁、模块化的零碎。
当咱们想要 主题化 某一模块时,能够在该模块的根元素中设置 CSS 变量,以便于变量能够向下传递,而不影响该模块以外的元素。
<html>
<body>
<div class="mod">
<p>
段落 1
</p>
</div>
<p>
段落 2
</p>
</body>
</html>
.mod {
--modBgColor: pink;
--modMainColor: blueviolet;
}
p {background: var(--modBgColor);
color: var(--modMainColor);
}
在 .mod
中申明的 CSS 变量将对 <p>
元素的“段落 1”可见,它是类名是 mod
节点的子元素,因而设置的背景色和字体色会对“段落 1”失效。
而 <p>
元素的“段落 2”款式不会受到影响,因为它不属于 .mod
或其子元素,CSS 变量 --modBgColor
和--modMainColor
对它不可见。
这就是 CSS 变量 作用域 的弱小之处。
变量赋值变量
CSS 变量也能够应用变量赋值变量,上面的例子中,应用 CSS 变量渲染突变背景色:
<div class="gradient"></div>
<div class="gradient"></div>
:root {
--color1: pink;
--color2: aquamarine;
--bg: linear-gradient(to right, var(--color1), var(--color2));
}
.gradient {
margin: 10px auto;
width: 200px;
height: 100px;
background: var(--bg);
}
变量不失效问题
当初,如果想让第二个模块渐变色变成从粉色过渡到薰衣草色,那就简略粗犷地给第二个模块加个类名 theme-2
,同时给变量—color2
赋值薰衣草色:
.theme-2 {--color2: lavender;}
然而变量并没有失效,问题在于 --bg
是在 :root
中被申明且被赋值了红到绿的突变值,能够应用这个变量是因为它是全局变量可拜访,在 theme-2
中批改的 —-color2
的值并不会更新 —-bg
的值,转换成 js 语句就容易了解了:
let color1 = 'red';
let color2 = 'aquamarine';
let bg = `${color1}-${color2}`;
function gradient() {
color2 = 'lavender';
console.log(bg);
}
gradient(); // red-aquamarine
解决办法:在应用变量的层级赋值
:root {
--color1: pink;
--color2: aquamarine;
}
.gradient {--bg: linear-gradient(to right, var(--color1), var(--color2));
background: var(--bg);
}
.theme-2 {--color2: lavender;}
把 —-bg
变量的赋值放到 .gradient
层级中,—-color2
变量就失效了:
须要正当应用
:root {
--prop1: lol;
--prop2: var(--prop1) var(--prop1);
--prop3: var(--prop2) var(--prop2);
--prop4: var(--prop3) var(--prop3);
...
--prop30: var(--prop29) var(--prop29);
}
如果无限度地渲染和运行,下面的代码段会导致浏览器尝试创立大概十亿个 —-prop1
值(’lol’)的实例,这足以让大多数零碎内存不足。这个例子在 2019 年的时候应用 32gb RAM 的 MacBook Pro 进行测试,30 秒运行后 Safari 进行响应。那时候所有 WebKit 内核的浏览器都容易通过 CSS 变量受到攻打,当初的浏览器已对该状况做相应的解决,被变量援用赋值超过 65536 次的变量会被当作有效值解决。
实战演练(举个🌰)
咱们能够在不同场景下妙用 CSS 变量的作用域这一个性,以下例子中演示了如何应用 CSS 变量实现一个可切换主题的开关。
https://codepen.io/bobolovecat/pen/vYZJPop
咱们创立了 2 个作用域范畴,别离是代表亮堂主题的 .theme-bright
和暗黑主题的.theme-dark
。在这两个部分作用域中应用雷同的变量名,各个变量只对主题相应的模块失效。
小结
利用 CSS 变量 的作用域个性和 var()的变量回退,有助于咱们设计一个代码整洁、模块化的零碎。但也要留神作用域层级和正当使用 CSS 变量赋值,防止代码构造过于简单以及影响页面渲染性能。
参考
The Big Gotcha With Custom Properties
A Complete Guide to Custom Properties
Understanding the Scope in CSS Variables – Part 2 – Webkul Blog