Open mengtuifrontend opened 5 years ago
如果用过 less\scss\stylus 等预处理 CSS 语言,那么你就不会对使用变量来简化我们的 CSS 开发工作感到陌生。但是你知道吗?CSS 现在也支持原生的变量了: var()。
var()
CSS 原生的变量如何使用?我们来看下:
.selector { --size: 16px; font-size: var(--size) }
这个简单的例子中,.selector 的 fontSize 值就是 16px。但是这么简单的例子凸显不出 CSS 变量的价值,我们来看个更能体现变量价值的例子:
.selector
fontSize
16px
body {--bg: #fff} p {background: var(--bg)} a {color: var(--bg)} span {border: 1px solid var(--bg)}
这个例子中,我们在 body 元素中定义了变量 --bg,并在其他三个标签上应用了变量,而且用于不同的 CSS 属性。变量无疑给我们开发 CSS 带来了便利和更好的维护性,简单修改变量值即可同时在不同 selector 和不同属性上生效。那么我们接下来再仔细看看 CSS 变量的一些特性。
body
--bg
selector
--*
CSS 变量有一个很明显的特点就是必须以 -- 起始,看起来很奇怪。早期的规范是以 var- 作为起始,所以在一些老版本浏览器中可能需要定义 var- 起始(firefox 31 以下 bug 985838)的变量名才能生效。
--
var-
我个人感觉有一个好处就是官方钦定了 CSS 变量名的烤肉串风格(Kebabs Style)写法(人都给你两个 - 了)。
-
和普通的 CSS 属性忽略大小写不同,变量名对大小写是敏感的。
body { --color: #f90; --Color: #f00; background: var(--color); /* #f90 */ }
建议变量名全小写,原因就是上面我们提到的,变量名使用烤肉串风格声明。
不同于预处理语法直接声明变量,CSS 变量必须声明在样式规则中,包括条件化规则 @media 等。
@media
--size: 20px; /* 语法错误 */ body { --size: 20px; /* 正确声明 */ }
但是在 @keyframes 中定义的变量会被作为动画属性。因为规范规定变量是 Animatable: no 的,不可以作为动画属性的。一旦在 @keyframes 中定义了变量,且有动画属性使用了该变量,那么这个属性将会受到影响,导致动画失效。
@keyframes
Animatable: no
@keyframe test { from { --color: #f00; background: var(--color)} to { --color: #fff; background: var(--color)} }
这种方式的写法,背景色不会出现变化哦。那该怎么做呢?一种方式就是多定义几个变量,比如:
@keyframe test { from { background: var(--color-start)} to { background: var(--color-end)} }
变量必须通过将变量名放入 var() 中进行引用,否则会被忽略。
body { --color: #f90; background: --color; /* 语法错误 */ background: var(--color) /* 正确 */ }
CSS 变量也遵循 CSS 的继承规则和级联优先级规则。比如,当一个规则使用了变量,但是自身没有定义该变量时,CSS 解析器会向上查找变量,试图使用父级、祖父级的变量。
.parent {--size: 20px} .parent .current {font-size: var(--size)} /* current 的规则并没有定义 --szie 变量,使用的是继承到的变量 */
当多条规则中有重复定义的变量时,解析器会按样式级联优先级来确定使用哪个值:
.current.more {--size: 20px;} /* 这条规则权重大,所以 --size 变量取值为 20px */ .current {--size: 10px}
注意没有继承关系时,可以存在多个同名变量。
<div class="one"></div> <div class="two"></div> <div class="three"></div>
.one {--size: 10px; font-size: var(--size)} .two {--size: 20px; font-size: var(--size)} .three {--size: 30px; font-size: var(--size)} /*等同于*/ .one {font-size: 10px} .two {font-size: 20px} .three {font-size: 30px}
如果需要默认值,可以在 var 方法中传入哦。
var
body {background: var(--bg, #f00)}
如果没有找到 --bg 变量,那么 #f00 会生效。
需要注意的是,在使用变量时可能出现非法值的情况:
body {--bg: 20px; background: var(--bg, #f00)}
这种情况下,规则会被解析为:
body {background: 20px}
最终 body 的背景色是透明,而不是我们在 var 中设置的默认值。也就是说,CSS 变量的默认值只在变量未声明的情况下生效,不会影响值与属性非法组合情况。
和 JS 中定义变量类似,CSS 变量也拥有变量提升的效果,但是也有差异。
console.log(a) // undefined var a = 1; console.log(a) // 1 //等同于 var a; console.log(a) a = 1; console.log(a)
JS 中变量只有声明会被提升,值还是按照正常的代码流程进行赋值。而 CSS 变量不仅声明被提升,值也会被提升。
body {background: var(--color); --color: #f00} /* 等同于 */ body {--color: #f00; background: var(--color)}
在定义变量之前使用变量,和定义变量之后使用变量效果相同。
上面的例子中我们都在 CSS 属性值的位置使用变量,那么我们可以将变量作为 CSS 属性吗?比如:
--prop : font-size; var(--prop): 12px
答案是:不可以。
虽然CSS 变量不能作为属性名,但是它可以使用另一个变量进行赋值或表达式计算:
body { --size: 10px; --big-size: calc(var(--size) * 2); }
此处,--big-size 变量的值为 20px。
--big-size
20px
赋值的时候我们需要注意给变量带上单位,如果在引用之后加上单位是不能正确解析的,如:
body { --size: 10; font-size: var(--size)px; /* 会被解析成 font-size: 10 px,数字 10 与 px 之间有一个空格 */ }
这种写法等同于给 CSS 属性设置了一个非法值。
规范中有提到可以使用 CSSOM 进行变量的获取与设置:
element.style.setProperty('--foo', '10px') element.style.setProperty('height', 'var(--foo)') // 设置元素 height 为 10px element.style.getPropertyValue('--foo') // 获取变量值,返回 10px
我们可以通过 DOM 对象的 style 属性进行 CSS 变量的取值和设置。
style
需要注意的事,只有 inline 到 DOM 对象的 CSS 变量能通过这种方式获取,写在 CSS 文件或 style 元素中的 CSS 变量的获取方式尚未找到,有知晓的朋友欢迎留言相告,感谢。
目前来看,CSS 变量在 PC 浏览器兼容性比较好,只有 IE 尚未实现。而移动端 IOS safari 已经实现了,安卓需要再等等就可以在生产使用。
当你看到这篇文章的时候可能有所变化,请前往 can i use 查看实时数据。
了解 CSS 变量
如果用过 less\scss\stylus 等预处理 CSS 语言,那么你就不会对使用变量来简化我们的 CSS 开发工作感到陌生。但是你知道吗?CSS 现在也支持原生的变量了:
var()
。基本用法
CSS 原生的变量如何使用?我们来看下:
这个简单的例子中,
.selector
的fontSize
值就是16px
。但是这么简单的例子凸显不出 CSS 变量的价值,我们来看个更能体现变量价值的例子:这个例子中,我们在
body
元素中定义了变量--bg
,并在其他三个标签上应用了变量,而且用于不同的 CSS 属性。变量无疑给我们开发 CSS 带来了便利和更好的维护性,简单修改变量值即可同时在不同selector
和不同属性上生效。那么我们接下来再仔细看看 CSS 变量的一些特性。变量声明
--*
格式CSS 变量有一个很明显的特点就是必须以
--
起始,看起来很奇怪。早期的规范是以var-
作为起始,所以在一些老版本浏览器中可能需要定义var-
起始(firefox 31 以下 bug 985838)的变量名才能生效。我个人感觉有一个好处就是官方钦定了 CSS 变量名的烤肉串风格(Kebabs Style)写法(人都给你两个
-
了)。大小写敏感
和普通的 CSS 属性忽略大小写不同,变量名对大小写是敏感的。
建议变量名全小写,原因就是上面我们提到的,变量名使用烤肉串风格声明。
变量必须声明在样式规则中
不同于预处理语法直接声明变量,CSS 变量必须声明在样式规则中,包括条件化规则
@media
等。但是在
@keyframes
中定义的变量会被作为动画属性。因为规范规定变量是Animatable: no
的,不可以作为动画属性的。一旦在@keyframes
中定义了变量,且有动画属性使用了该变量,那么这个属性将会受到影响,导致动画失效。这种方式的写法,背景色不会出现变化哦。那该怎么做呢?一种方式就是多定义几个变量,比如:
引用变量
变量必须通过将变量名放入
var()
中进行引用,否则会被忽略。继承与级联优先级
CSS 变量也遵循 CSS 的继承规则和级联优先级规则。比如,当一个规则使用了变量,但是自身没有定义该变量时,CSS 解析器会向上查找变量,试图使用父级、祖父级的变量。
当多条规则中有重复定义的变量时,解析器会按样式级联优先级来确定使用哪个值:
注意没有继承关系时,可以存在多个同名变量。
默认值
如果需要默认值,可以在
var
方法中传入哦。如果没有找到 --bg 变量,那么 #f00 会生效。
需要注意的是,在使用变量时可能出现非法值的情况:
这种情况下,规则会被解析为:
最终 body 的背景色是透明,而不是我们在
var
中设置的默认值。也就是说,CSS 变量的默认值只在变量未声明的情况下生效,不会影响值与属性非法组合情况。变量提升
和 JS 中定义变量类似,CSS 变量也拥有变量提升的效果,但是也有差异。
JS 中变量只有声明会被提升,值还是按照正常的代码流程进行赋值。而 CSS 变量不仅声明被提升,值也会被提升。
在定义变量之前使用变量,和定义变量之后使用变量效果相同。
变量赋值
上面的例子中我们都在 CSS 属性值的位置使用变量,那么我们可以将变量作为 CSS 属性吗?比如:
答案是:不可以。
虽然CSS 变量不能作为属性名,但是它可以使用另一个变量进行赋值或表达式计算:
此处,
--big-size
变量的值为20px
。赋值的时候我们需要注意给变量带上单位,如果在引用之后加上单位是不能正确解析的,如:
这种写法等同于给 CSS 属性设置了一个非法值。
CSSOM 进行动态设置 CSS 变量
规范中有提到可以使用 CSSOM 进行变量的获取与设置:
我们可以通过 DOM 对象的
style
属性进行 CSS 变量的取值和设置。需要注意的事,只有 inline 到 DOM 对象的 CSS 变量能通过这种方式获取,写在 CSS 文件或 style 元素中的 CSS 变量的获取方式尚未找到,有知晓的朋友欢迎留言相告,感谢。
兼容性
目前来看,CSS 变量在 PC 浏览器兼容性比较好,只有 IE 尚未实现。而移动端 IOS safari 已经实现了,安卓需要再等等就可以在生产使用。
当你看到这篇文章的时候可能有所变化,请前往 can i use 查看实时数据。
参考文献
Thanks