学习CSS Variable(CSS变量)以及实现JS与CSS变量交互

浏览器支持情况

请看浏览器支持状况,就目前国内而言,移动混合开发、微信开发,都支持CSS变量。PC端不可考虑。

基本用法

全局用法

这是全局作用域的css变量以及用法:

:root {
    --main-color: #f40;
    --block-font-size: 10px;
}

.aaa {
    color: var(--main-color);
}

任何地方想使用变量,只需要var()这个变量即可。

局部用法

这是局部作用域的css变量以及用法:

<style>
.a {
  --main-color: #f40;
  --block-font-size: 10px;
}

.aaa {
    color: var(--main-color);
}
</style>
</head>
<body>
    <div class="a">
        <p class="aaa">否定伪类选择符 E:not(s)</p>
    </div>

</body>

也就是说,变量可以像普通声明一样写在某个类(或其他任何选择器)里,就可以影响所有后代选择器。

变量名规定

css变量名跟js的变量名比起来宽松得多,比如可以使用数字作为变量名,但是一些IDE会有警告。所以,为了不引起歧义,还是尽量使用严苛的变量名起名法则,跟js保持一致就行了。最后,别忘了前面加两个-

变量值规定

一句话,凡是css合法值,都可以作为变量值,并不限于单个值,比如20px 20px 20px是合法的。

调用规定

必须按照语法var( <自定义变量名> [, <默认值 ]? )来写,可以是var(--aa)也可以是var(--aa, 20px 20px),逗号后面的值就是默认值,当变量名不存在的时候,默认值生效。

可以连续使用var拼接成一个css属性值:margin: var(--aa) var(--bb);

下面这个例子中,没有bb这个变量,但是后面的默认值本身又带有逗号,这种写法是否合法呢?

.aaa {
    color: rgb(var(--bb, 255, 255, 255));
}

是合法的,也就是说,浏览器会把第一个逗号之后的内容一概当做默认值。

当变量值书写错误,那么就算引用变量的时候默认值纠正正确,也无济于事,会出错。比如:

body {
  --color: 20px;
  background-color: #369;
  background-color: var(--color, #cd0000);
}

background-color是不可能值为20px的,那么你用#cd0000纠正也没有用,此时background-color会等于默认值rgba(0, 0, 0, 0),也就是透明。所以,千万别写错。

变量引用

一个变量比如--aa,可以被--bb引用:

body {
  --aa: 3px;
  --bb: var(--aa);
}

结合calc计算

一句话说,该怎么写就怎么写,变量值的变化会引起重新计算。

变量重新赋值

就像js变量一样,css变量可以重新赋值,这种重新赋值跟书写顺序相关,也跟js一样。比如:

<style>
.a {
  --mar: 20px 20px;
}

.b {
    margin: var(--mar);
}

.c {
    --mar: 40px 40px;
}

.d {
    margin: var(--mar);
}
</style>
</head>
<body>
    <div class="a">
        <div class="b">
            <div class="c">
                <div class="d"></div>
            </div>
        </div>
    </div>
</body>

这里.d的margin就不是20px 20px。

需要强调的是,变量重新赋值会导致依赖它的其他变量的值也会改变,这跟js是一致的。比如:

.box {
    --columns: 4;
    --margins: calc(24px / var(--columns));
    --space: calc(4px * var(--columns));
    --fontSize: calc(20px - 4 / var(--columns));
}
@media screen and (max-width: 1200px) {
    .box {
        --columns: 3;
    }
}
@media screen and (max-width: 900px) {
    .box {
        --columns: 2;
    }
}
@media screen and (max-width: 600px) {
    .box {
        --columns: 1;
    }
}

当浏览器宽度有变化的时候,--columns会变化,连带--margins、--space、--fontSize会一起发生变化,所以只需要改变--columns就可以了。

js向css传值

js给css变量传值的办法是使用el.style.setProperty()方法,比如:

    <style>
    .b {
        color: var(--theme-color);
    }
    </style>
    <div class="a">a
        <div class="b">b
            <div class="c">c
                <div class="d">d</div>
            </div>
        </div>
    </div>
    <script>
    const aEl = document.querySelector('.a');
    aEl.style.setProperty('--theme-color', 'red');
    </script>

给a元素设置变量,会影响自身和所有后代元素,但是如果.a自身并没有写color: var(--theme-color);,那么就可以做到只影响后代元素,不影响自身。

如果想给自身和后代元素设置默认值(即blue),可以写一条:

.a {
  --theme-color: blue;
}

js读取css变量

读取办法是使用window.getComputedStyle(aEl).getPropertyValue('--theme-color')方法。比如:

    <style>
.a {
  --theme-color: blue;
}
    .b {
        color: var(--theme-color);
    }
    </style>
    <div class="a">a
        <div class="b">b
            <div class="c">c
                <div class="d">d</div>
            </div>
        </div>
    </div>
    <script>
    const aEl = document.querySelector('.a');
    const themeColor = window.getComputedStyle(aEl).getPropertyValue('--theme-color');
    console.log(themeColor); // blue
    </script>