Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

了解 CSS 变量 #82

Open
ajccom opened this issue Mar 27, 2017 · 0 comments
Open

了解 CSS 变量 #82

ajccom opened this issue Mar 27, 2017 · 0 comments

Comments

@ajccom
Copy link
Contributor

ajccom commented Mar 27, 2017

了解 CSS 变量

如果用过 less\scss\stylus 等预处理 CSS 语言,那么你就不会对使用变量来简化我们的 CSS 开发工作感到陌生。但是你知道吗?CSS 现在也支持原生的变量了: var()


基本用法

CSS 原生的变量如何使用?我们来看下:

.selector {
  --size: 16px;
 font-size: var(--size)
}

这个简单的例子中,.selectorfontSize 值就是 16px。但是这么简单的例子凸显不出 CSS 变量的价值,我们来看个更能体现变量价值的例子:

body {--bg: #fff}
p {background: var(--bg)}
a {color: var(--bg)}
span {border: 1px solid var(--bg)}

这个例子中,我们在 body 元素中定义了变量 --bg,并在其他三个标签上应用了变量,而且用于不同的 CSS 属性。变量无疑给我们开发 CSS 带来了便利和更好的维护性,简单修改变量值即可同时在不同 selector 和不同属性上生效。那么我们接下来再仔细看看 CSS 变量的一些特性。


变量声明

--* 格式

CSS 变量有一个很明显的特点就是必须以 -- 起始,看起来很奇怪。早期的规范是以 var- 作为起始,所以在一些老版本浏览器中可能需要定义 var- 起始(firefox 31 以下 bug 985838)的变量名才能生效。

我个人感觉有一个好处就是官方钦定了 CSS 变量名的烤肉串风格(Kebabs Style)写法(人都给你两个 - 了)。


大小写敏感

和普通的 CSS 属性忽略大小写不同,变量名对大小写是敏感的。

body {
  --color: #f90;
  --Color: #f00;
  background: var(--color); /* #f90 */
}

建议变量名全小写,原因就是上面我们提到的,变量名使用烤肉串风格声明。


变量必须声明在样式规则中

不同于预处理语法直接声明变量,CSS 变量必须声明在样式规则中,包括条件化规则 @media 等。

--size: 20px; /* 语法错误 */

body {
  --size: 20px; /* 正确声明 */
}

但是在 @keyframes 中定义的变量会被作为动画属性。因为规范规定变量是 Animatable: no 的,不可以作为动画属性的。一旦在 @keyframes 中定义了变量,且有动画属性使用了该变量,那么这个属性将会受到影响,导致动画失效。

@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 方法中传入哦。

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

赋值的时候我们需要注意给变量带上单位,如果在引用之后加上单位是不能正确解析的,如:

body {
  --size: 10;
  font-size: var(--size)px; /* 会被解析成 font-size: 10 px,数字 10 与 px 之间有一个空格  */
}

这种写法等同于给 CSS 属性设置了一个非法值。


CSSOM 进行动态设置 CSS 变量

规范中有提到可以使用 CSSOM 进行变量的获取与设置:

element.style.setProperty('--foo', '10px')
element.style.setProperty('height', 'var(--foo)') // 设置元素 height 为 10px
element.style.getPropertyValue('--foo') // 获取变量值,返回 10px

我们可以通过 DOM 对象的 style 属性进行 CSS 变量的取值和设置。
需要注意的事,只有 inline 到 DOM 对象的 CSS 变量能通过这种方式获取,写在 CSS 文件或 style 元素中的 CSS 变量的获取方式尚未找到,有知晓的朋友欢迎留言相告,感谢。


兼容性

目前来看,CSS 变量在 PC 浏览器兼容性比较好,只有 IE 尚未实现。而移动端 IOS safari 已经实现了,安卓需要再等等就可以在生产使用。

当你看到这篇文章的时候可能有所变化,请前往 can i use 查看实时数据。


Thanks

参考文献

@ajccom ajccom changed the title CSS3 变量的使用与不足 了解 CSS 变量 Mar 27, 2017
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

2 participants