css 小师系列: 一文快速了解css变量!

307 阅读2分钟

各位是否在工作中仅仅使用css处理器,比如sass,less在定义变量呢?殊不知css也已经支持定义变量,那么css变量要如何使用,有何优缺点呢,别着急,这篇文章带你快速入门css变量!

go.gif

概念

首先来介绍下,CSS 变量是用来存储 CSS 值的自定义属性,其语法以 -- 开头,属于元素的 样式属性(Style Property) ,可以在 CSS 中像普通属性值一样被引用。

举个例子,下面代码里 --main-color 就是一个css变量:

.button {
  --main-color: #e74c3c;
}

为什么选择用--表示变量呢?因为$foo被 Sass 用掉了,@foo被 Less 用掉了。为了不产生冲突,官方的 CSS 变量就改用两根连词线。🤪

定义了变量后,如何使用呢?这里我们要用到 css 提供的 var 函数,用法如下:

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

它有第二个参数,用于指定回退值,如果前面的变量不存在,则会使用默认值,如下:

.button{
    color:var(--main-color,red);
}

// 多层嵌套也是可以的
.button{
    color:var(--main-color,var(--second-color,red));
}

ok,现在你已经了解了如何定义和使用css变量,但是不要忘了下面这些注意事项:

变量是有作用域的,要存在于css块里(即{}中),最高优先级的生效,子元素会继承父元素

举个例子,来看下面代码:

// 不生效
--color:orange;
//会被上述定义错误的变量影响,也不会生效
:root { --color: blue; }
div { --color: green; }
#alert { --color: red; }
* { color: var(--color); }

除了没有在css块里的变量失效,紧随其后的样式也受到了影响。其他的则会根据优先级去匹配。

那么如何定义全局变量呢?一般是定义在:root下,也就是上面被影响到的那个。😅

变量可以是字符串,也可以是数值

比如下面这段代码,就是变量为字符串的情况:

:root{
    --bar: 'hello';
    --foo: var(--bar)' world';
}

body:after {
  content: var(--bar)var(--foo);
}

这里要注意,首先变量不允许用作属性名,下面这样是无效的:

.foo {
  --side: margin-top;
  /* 无效 */
  var(--side): 20px;
}

如果变量值带有单位,就不能写成字符串。比如下面的例子:

/* 无效 */
.foo {
  --foo: '20px';
  font-size: var(--foo);
}

/* 有效 */
.foo {
  --foo: 20px;
  font-size: var(--foo);
}

再举一个变量为数值的例子:

.foo {
  --gap: 20;
  margin-top: calc(var(--gap) * 1px);
}

这里使用calc函数是因为数值类型的变量不能直接和单位写在一起

JS可以操作css变量

大致方法如下:

// 设置变量
document.body.style.setProperty('--primary', '#7F583F');

// 读取变量
document.body.style.getPropertyValue('--primary').trim();
// '#7F583F'

// 删除变量
document.body.style.removeProperty('--primary');

可以利用标签的style属性来定义变量,并且可以在css文件中直接使用

比如下面这个标签:

<div id="g-element" style="--bgColor: #000"></div>

在对应的css文件中,如果对应选择器匹配上上面这个div,就可以直接使用--bgColor

只要语法是正确的,var函数都会解析,而不会关注值的合法性

如果变量值不合法,则采用默认值。

比如下面这段代码,最后背景颜色是什么呢?没错,是透明,即默认值

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

解释下发生了什么,首先由于没有语法问题,因此最后生效的是background-color: var(--color, #cd0000);这里,然后,--color的值为20px,因此,对应的就是,background-color:20px,显然这是不对的,于是采用默认值,也就是透明,最后实际生效的样式如下图:

image.png

不要产生循环依赖

循环依赖产生有以下两个场景:

  1. 变量需要依赖其自身值。即,定义时就使用了var()引用其值。如下:
:root {
    --m: var(--m)
}
  1. 两个或两个以上的变量互相引用时
:root {
    --one: calc(var(--two) + 10px);
    --two: calc(var(--one) - 10px);
}

要避免上述两种情况。

使用场景

简单列举几个使用场景:

首先是响应式布局,CSS 是动态的,页面的任何变化,都会导致采用的规则变化。

利用这个特点,可以在响应式布局的media命令里面声明变量,使得不同的屏幕宽度有不同的变量值。如下:

body {
  --primary: #7F583F;
  --secondary: #F7EFD2;
}

a {
  color: var(--primary);
  text-decoration-color: var(--secondary);
}

@media screen and (min-width: 768px) {
  body {
    --primary:  #F7EFD2;
    --secondary: #7F583F;
  }

然后是主题切换,在 antd 中就支持使用css变量的形式去修改主题,可以查看这个链接antd使用css变量修改主题

变量也可简化一些动画相关的代码,除了常规的抽取相同的值之外,我们还可以巧妙的将一些动画变换转为对变量的变换,比如下面这个例子:CodePen Home MASK conic-gradient 转场 其核心是下面这段代码:

@keyframes maskRotate {
    @for $i from 0 through 100 { 
        #{$i}% {
            mask: conic-gradient(#000 #{$i - 8 + '%'}, transparent #{$i + '%'}, transparent);
        }
    }
}

经过编译后,要生成101个关键帧,而采用css变量,则可以优化成这样:

@property --per {
  syntax: '<percentage>';
  inherits: false;
  initial-value: -10%;
}

div {
    position: relative;
    width: 400px;
    height: 400px;
    background: url(https://picsum.photos/400/400?random=5) no-repeat;

    &::before {
        content: "";
        position: absolute;
        top: 0;left: 0; right: 0;bottom: 0;
        background: url(https://picsum.photos/400/400?random=100) no-repeat;
        mask: conic-gradient(
            #000 0, 
            #000 var(--per), 
            transparent calc(var(--per) + 10%), 
            transparent
        );
        z-index: 1;
        animation: maskRotate 5s ease-in forwards;
    }
}

@keyframes maskRotate {
    0% {
        --per: -10%;
    }
    100% {
        --per: 100%;
    }
}

其中CSS  @Property at-rule 是 CSS Houdini API 的一部分,它允许开发者显式地定义他们的 CSS 自定义属性,允许进行属性类型检查、设定默认值以及定义该自定义属性是否可以被继承。

简单理解就是CSS 自定义属性(CSS 变量)。

通过这种方式将原先生成101个关键帧变为修改 css 变量,是不是很巧妙呢?

总结

相信通过这篇文章,大家一定对css变量有了更深入全面的理解,想不想立刻在自己的项目里使用下试试呢?快去操练起来吧!😎

(ps.感谢大家阅读,看到这,不妨点个赞在走吧,十分感谢!😍)

往期文章

css 小师系列:蝉原则

css 小师系列:mask?

css 小师系列:一种新的影响样式优先级的方式😍

css 小师系列:为什么 background 渐变可以叠加,而颜色不可以?