一、简介
CSS的自定义属性,又称为CSS变量或级联变量,用于定义一个带有值的、可重复使用的CSS属性(变量)。其包含的值可以在其作用域内的任意属性上重复使用,在使用时需要借助var()
函数获取自定义属性的值。当自定义属性的值发生变化时,所有使用该自定义属性的CSS属性都会随之变化。
通常会将项目中大量重复的样式属性值设置为自定义属性,例如:字体颜色、字体大小、主题色等等。这不仅提高了代码的可维护性和可读性,还使得样式的动态调整变得更加容易。当这些样式属性的值,需要变更时,只需要修改自定义属性的值即可,无需依次修改对应CSS样式属性的值。
在使用自定义属性时,要注意浏览器兼容性:
二、基础语法
1、声明自定义属性
声明一个自定义属性,需要在CSS的某个样式块(规则集)中,且必须以--
作为属性名的开头,后面跟随其他合法字符组成自定义属性的属性名。属性值可以是任何有效的CSS样式值。
element {
--test-color: red;
}
自定义属性所在样式块的选择器决定了自定义属性的作用域,自定义属性只能在该选择器元素及其子孙元素中使用。如果想要设置一个全局的自定义属性,最佳实践是定义在根伪类:root
的样式块内,这样就可以在HTML全局任何样式块中使用该自定义属性:
:root {
--test-color: red;
}
注意: 自定义属性的名称是严格区分大小写的,--test
与--Test
是两个完全不同的自定义属性。
2、使用自定义属性
想要使用自定义属性,需要借助CSS的var()
函数。var()
函数需要放置在CSS样式的属性值位置上,内部包含一个自定义属性的名称。函数会寻到找对应的自定义属性,并把自定义属性的值插入作为当前样式的属性值。
.test-div {
color: var(--test-color);
}
/* 样式效果等同于 */
.test-div {
color: red;
}
无论自定义属性是在样式块中的哪一行进行的声明,其都可以在当前样式块内的任意属性上被使用,无论该属性是位于自定义属性声明之前,还是自定义属性声明之后。
.test-div {
/* 自定义属性声明之前的样式可以使用 */
color: var(--test-color);
/* 声明自定义属性 */
--test-color: red;
/* 自定义属性声明之后的样式可以使用 */
background: var(--test-color);
}
3、继承
后代元素会继承父元素中声明的自定义属性,在后代元素中可以使用到父元素中的自定义属性,换句话说:自定义属性可以在该选择器元素及其子孙元素中使用。
<template>
<div class="father">
<div class="son1">
这是一个子元素
<p>这是一个孙子元素</p>
</div>
</div>
</template>
<style scoped>
/* 父元素中定义自定义属性 */
.father {
--test-color: red;
}
/* 子元素可以继承并使用该自定义属性 */
.son1 {
color: var(--test-color);
}
/* 后代元素也可以继承并使用该自定义属性 */
.son1 > p {
color: var(--test-color);
}
</style>
4、优先级
如果在不同层级的样式块中定义了同名的自定义属性,则var()
函数获取自定义属性值时,会按照就近原则获取。
例如父元素定义了名为--test-color
的自定义属性,而子元素同样定义了名为--test-color
的自定义属性,则在子元素和孙子元素中通过var(--test-color)
使用自定义属性时,按照就近原则,获取的将会是子元素中自定义属性的值。
<template>
<div class="father">
<div class="son1">
这是一个子元素
<p>这是一个孙子元素</p>
</div>
<div class="son2">
这是第二个子元素
</div>
</div>
</template>
<style scoped>
.father {
/* 父元素声明的自定义属性 */
--test-color: red;
}
.son1 {
/* 子元素声明的同名自定义属性 覆盖父元素 */
--test-color: yellow;
/* 就近原则 取到最近子元素的自定义属性 */
color: var(--test-color);
}
.son1 > p {
/* 孙子元素 取到子元素的自定义属性 */
color: var(--test-color);
}
.son2 {
/* 就近原则 子元素取到父元素的自定义属性 */
color: var(--test-color);
}
</style>
还有一条原则是:style
行内样式中声明的自定义属性,其优先级大于CSS样式块中声明的自定义属性,最终通过var()
使用自定义属性时,生效的是style
行内样式中声明的自定义属性。
5、备用值(默认值)
在通过var()
函数使用自定义属性时,可以定义备用值,当自定义属性未定义或无法获取时,浏览器会将备用值设置为样式属性值。
var()
函数有两个参数,第一个参数是引用的自定义属性名称,第二个可选参数就是备用值。备用值可以包含除换行符、分号等特殊字符外的常见字符。
/* 当自定义属性未定义时 取备用值 */
color: var(--test-color2, green);
var()
函数允许在备用值中嵌套var()
,但并不建议这么做,因为这可能会花费大量的时间在处理变量上,导致性能问题。
/* var()中嵌套var() */
color: var(--test-color2, var(--test-color, green));
备用值中允许使用,
连接多个值,但浏览器并不会将这些值进行分割,而是会将其作为一个整体,赋值给样式属性,通常来说,这样设置的属性值都是无效值。如果自定义属性是未定义的,且备用值也是无效的,那该样式属性将不会起作用,元素将会展示默认样式。
/* var()的备用值中使用 , 拼接多个值 */
color: var(--test-color2, green, blue);
/* 等同于 */
color: green, blue;
注意: 如果是浏览器不支持CSS自定义属性,那么设置备用值也不会起作用。
6、无效属性
当自定义属性被解析时,浏览器并不知道其会在什么场景下使用,因此默认自定义属性的值都是有效的。但在具体使用自定义属性时,如果自定义属性的值与样式属性不匹配,就会导致样式属性成为一条无效属性。
当浏览器遇到这种无效属性时,var()
的备用值也不会起作用,因为确确实实是取到了值。元素最终的样式效果,会使用元素去掉该样式属性后的效果。
/* 当自定义属性无效时 备用值无效 取元素本身样式 */
font-size: var(--test-color, 40px);
/* 等同于 无效属性 */
font-size: red;
注意: 当CSS中的属性值存在语法错误时,该属性会直接被忽略,如果还存在其他同名且合法的属性,则其他属性会正常起作用;但是如果是获取的自定义属性的值无效,其并不会被忽略,其他同名且合法的属性也会被该属性覆盖,从而不起作用,只能显示元素去掉该样式属性后的效果。
.son1 {
/* 一个合法的属性 最终起作用 */
font-size: 30px;
/* 不合法的属性 会被忽略 */
font-size: red;
}
.son2 {
/* 一个合法的属性 会被无效属性覆盖 */
font-size: 30px;
/* 当自定义属性无效时 覆盖其他属性 只能展示元素本身的样式 */
font-size: var(--test-color);
}
7、JavaScript操作
CSS的自定义属性还给我们提供了一种新的JS与CSS交互的方式,可以在JS中直接操控元素的CSS样式,实现样式的动态变化。在JS中,可以通过setProperty()
方法设置或修改CSS自定义属性的值。该方法相当于设置了一个style
行内样式,并在其中设置了一个自定义属性,这一点在DOM节点上也有所的体现。
声明自定义属性:
// 获取元素DOM
const el = document.querySelector('.father')
// 设置元素的CSS自定义属性的值
el.style.setProperty('--test-color', 'blue')
DOM节点:
<div class="father" style="--test-color: blue;">
...
</div>
修改自定义属性:
在JS中只能修改style
行内样式中的自定义属性(手动定义或setProperty
设置),CSS样式块中的自定义属性无法修改,但是当在style
行内样式中声明一个同名的自定义属性,由于其优先级高于CSS样式块中的自定义属性,因此起作用的是新声明的自定义属性。从效果来看,也算是修改了自定义属性的值,但并非真正意义的修改。
// 获取元素DOM
const el = document.querySelector('.father')
// 修改元素的CSS自定义属性的值
el.style.setProperty('--test-color', 'red')
获取自定义属性值:
在JS中还可以通过getPropertyValue()
获取style
行内样式中的自定义属性(手动定义或setProperty
设置)。同样,CSS样式块中的自定义属性无法被获取到。
<!-- 手动指定一个行内的自定义属性 -->
<div class="father" style="--test-color: #ccc">
<!-- 。。。 -->
</div>
<script>
// 获取元素DOM
const el = document.querySelector('.father')
// 获取元素style中的自定义属性的值
console.log(el.style.getPropertyValue('--test-color')) // #ccc
// 修改元素的自定义属性的值
el.style.setProperty('--test-color', 'blue')
// 再次获取元素style中的自定义属性的值
console.log(el.style.getPropertyValue('--test-color')) // blue
// 获取CSS样式块中的自定义属性 无法获取
console.log(el.style.getPropertyValue('--test-size')) // 空
</script>
<style>
.father {
/* 样式块中的自定义属性 */
--test-size: 20px;
}
</style>