阅读 2353

我总结的 CSS 变量知识点

摄影 | Eliott Reyna

最近读到一篇文章《Everything you need to know about CSS Variables》,让我对 CSS 变量有了新的认识。下面将整理出来的跟自己感悟的地方与大家分享,希望能帮助到对 CSS 变量还一知半解的同学。

答疑

一、为什么 CSS 变量还称为“自定义属性(custom properties)”?

我们回忆 CSS 变量的使用方式:

span {
    /* 局部变量 --color */
    --color: gold;
    color: var(--color);
}
复制代码

声明 CSS 变量的时候,发现跟使用普通属性是一样的,这里说的“一样”是指:使用的位置一样,并且使用的方式也一样。

只不过跟普通属性相比,CSS 变量多了两个连字符 -- 作为前缀,本质上就是个属性。而且这类属性都是开发者自己起的,属性值也是我们设置的,自然就是“自定义属性”了。

不过特殊的地方在于,我们可以使用 var() 函数解析出这类属性的属性值:

color: var(--color);
/* 相当于 */
color: gold;
复制代码

还有一点,CSS 变量既然是属性,那么就可以像行内样式那样使用:

<span style="--color: gold; color: var(--color);">这段文本是金色的</span>
复制代码

文章后面“使用 JS 操作 CSS 变量”一节,就是基于此种写法实现的。之后会讲到,咱们先继续往下看。

二、全局变量和局部变量

全局变量是这样声明的:

:root {
    --color: gray;
}
复制代码

:root 伪类命中的是文档根元素 <html>,也就说

:root {
    --color: gray;
}
/* 相当于 */
html {
    --color: gray;
}
复制代码

根元素是文档的最顶层元素,在它下面声明的变量就是全局变量。对应的,不是全局的变量就是局部变量。

<style>
:root {
    /* 全局变量 --color */
    --color: gray;
}

p {
    /* 局部变量 --color */
    --color: gold;
    color: var(--color);
}
</style>

这段文本是灰色的,<span>这段文本是金色的</span>
复制代码

与 JS 作用域类似的是,局部变量会覆盖全局中的同名变量。因此上面 <span> 里的文本是金色的。

三、var() 解析出来的结果只能作为属性值使用

下面这样写是不行的:

.mt-20px {
    --mt: margin-top;
    var(--mt): 20px; /* × 这种写法是错误的 */
}
复制代码

我们想要可能是这种结果:margin-top: 20px,但观察发现,浏览器并不会解析 var(--mt),而且提示这是一个未知属性名。

下面这样写就没有问题了:

.mt-20px {
    --20px: 20px;
    margin-top: var(--20px); /* √ 这样写就没问题了 */
}
复制代码

四、var() 的回退值(fallback)

var() 功能符,还接受第二个参数,表示一个回退值——当变量不能成功解析时,就会使用这个回退值。

.header {
    color: var(--header-color, blue);
}
复制代码

上面代码中,如果 --header-color 没有声明的话,就会使用回退值 blue,作用有点类似于 JS 函数中的参数默认值。

五、使用 calc() 做数学运算

如果声明的变量值中包含数学运算,就要包装在 calc() 函数中。否则是无效运算。

像下面这种写法就不对:

.font-40px {
    --size: 20px * 2; /* × 错误的写法 */
    font-size: var(--size);
}
复制代码

在浏览器中观察,不会看见显式的报错,但 font-size 的最终解析值仍是默认的 16px

这种错误写法在浏览器中并不会显式报错

`font-size` 的最终的解析值仍是 `16px`

需要这样写:

.font-40px {
    --size: calc(20px * 2); /* √ 正确的写法 */
    font-size: var(--size);
}
复制代码

calc() 函数的引入,为在 CSS 中进行各种不同单位的混合数值运算(加、减、乘、除),带来了极大的便捷:

.example {
    /* 加 */
    width: calc(100% + 1em);
    /* 减 */
    width: calc(100% - 80px);
    /* 乘 */
    width: calc(100% * .5);
    /* 除 */
    width: calc(100% / 6);
}
复制代码

这里抛砖引玉,更多的使用细节可以查看 MDN 上的文档

六、使用 JS 操作 CSS 变量

JS 操作 CSS 变量的原理,是使用 DOM 对象的 style 属性,它是一个 CSSStyleDeclaration 类型的对象。

我们之前可能做过这样的操作:

document.body.style.color = 'gold'
复制代码

color 是标准属性,可以直接使用这种方式设置。CSS 变量则属于非标准属性,使用这种方法就不会起作用:

// × 错误的写法,因为 --color 并不是标准属性
document.body.style['--color'] = 'gold'
复制代码

CSSStyleDeclaration 上提供了一个 setProperty() 方法,可以用来设置非标准属性。语法如下:

style.setProperty(propertyName, value, priority);

因此,我们可以这么做:

document.body.style.setProperty('--color', 'gold');
复制代码

执行结果如下:

这样,咱们就能通过 JS 操作 CSS 变量了。

实践

CSS 变量的使用,在一定程度上改变了我们书写、组织代码的形式。其原理在于,我们能够修改已有变量的值。

下面我举两个比较有代表性的案例:

  1. 主题按钮
  2. 元素的 transform 变换

主题按钮

我们有四个主题色的按钮,在不同的场景下使用。使用以前的写法,是通过覆盖属性的方式实现的:

.btn {
    color: #333;
    background-color: #eee;
    border: 0;
    padding: .5rem;
    cursor: pointer;
}

.btn-success {
    color: #fff;
    background-color: green;
}

.btn-error {
    color: #fff;
    background-color: red;
}

.btn-warning {
    background-color: orange;
}
复制代码

如果使用变量,就不需要覆盖属性,直接修改变量值即可。

.btn {
    color: var(--btn-color, #333);
    background-color: var(--btn-bg-color, #eee);
    border: 0;
    padding: .5rem;
}

.btn-success {
    --btn-color: #fff;
    --btn-bg-color: green;
}

.btn-error {
    --btn-color: #fff;
    --btn-bg-color: red;
}

.btn-warning {
    --btn-bg-color: orange;
}
复制代码

demo 地址查看这里:codepen.io/zhangbao/pe…

元素的 transform 变换

先看看最终的效果图:

demo 地址:codepen.io/zhangbao/pe…

实现原理是这样的:我们在拖拉 Range Input 的时候,获取当前的 value 值,设置为变量 --slider 的值,.color-boxes 使用了此变量设置自身的 Y 轴偏移度。

涉及到的核心代码如下:

CSS:

.color-boxes {
    transform: perspective(500px) rotateY( calc(var(--slider) * 1deg));
}
复制代码

JS

const range = document.querySelector('.booth-slider')

range.addEventListener('input', handleSlider)
function handleSlider (e) {
  document.documentElement.style.setProperty('--slider', e.target.value)
}
复制代码

嗯,很神奇。

最后

本篇文章是我在看了一篇技术文章后总结的知识点,并加上了自己的一些感悟。如果看完后帮到了你,我将感到万分荣幸!😁

(完)

文章分类
前端
文章标签