CSS中的变量

1,084 阅读4分钟

现在业务中经常会使用一些 CSS 的预处理器或后处理器,他们极大的方便了开发过程中的 CSS 片段复用。但其实 CSS 原生也做出了一些改变,在兼容性没有那么苛刻的情况下, 可以尝试使用。本文就是我对 CSS 原生变量的探讨和认知。

简介

跟 JS 中的变量一样,目的都是为了复用并且减少 CSS 值的冗余。

比如这里的 1,2,3 处我们可以这么定义

.tabTitle {
  color: #007fff;
}
.tabSubtitle {
  color: #007fff;
}
.hot {
  color: #007fff;
}

都是使用的相同颜色,这么写没大问题,但是如果有一天设计师让我们修改这个颜色的时候就需要修改所有的地方,变量的方便就体现出来了。

:root {
  --main-color: #007fff;
}
.tabTitle {
  color: var(--main-color);
}
.tabSubtitle {
  color: var(--main-color);
}
.hot {
  color: var(--main-color);
}

这就是变量的基本用法 :root是定义变量作用域(scope)为根作用域,其含义为<html>标签下的作用域,相当于 js 中的全局作用域。

变量名称

变量名只能数字,字母以及_-,其余符号均为非法。空格都是不允许的

/*合法*/
:root {
  --main_color: #007fff;
  --_main-color: #007fff;
  --1_main_color: #007fff;
}
/*非法*/
:root {
  --main color: #007fff;
  --_main#$%^color: #007fff;
}

作用域

任意元素均可作为 CSS 变量的作用域;

:root {
  --main-color:  #007fff;
}
.title {
  --main-color: red;
  color: var(--main-color);
}

fallback

这里的备选并不是指如果浏览器不支持 CSS 变量而使用的备选值。

.title {
  color: var(--main-color, green);
}

这里是如果main-color没有被定义的话, 则使用green的 fallback。而且该值可以任意嵌套

.title {
  color: var(--main-color, var(--sub-color, green));
}

如果没有定义值, 也没有备选值, 那么该属性将会被忽略。

典型 cases

控制一个组件的大小

假设有三个不同大小的按钮:small, medium, large

<div class="button">primary</div>
<div class="button button--small">primary</div>
<div class="button button--large">primary</div>

css对应为

.button {
  --unit: 1em;
  padding: var(--unit)
}
.button--small {
  --unit: 0.5em;
}
.button--large {
  --unit: 1.5em;
}

HSL 颜色

HSL 表示 hue(色值),Saturation(饱和度), brightness(亮度)hue 决定了颜色,satuation和 brightness 决定这个颜色的亮和暗。

如果要实现一个 button 在 hover 的时候亮度减少为原来的 1/3,除了重写 background-color 之外,可以使用 css 变量更优雅的处理。

:root {
  --hue: 221;
  --sat: 71%;
  --bri: 48%;
}
.button {
  background-color: hsl(var(--hue), var(--sat), var(--bri));
  transation: background-color .3s ease-in-out;
}
.button:hover {
  --bri: 33%
}

按比例 resize

css 使用变量可以很轻易的实现。

.icon {
  --size: 22px;
  width: var(--size);
  height: var(--size);
}
<button class="add" >add</button>
<div class="icon"></div>

document.querySelector('.add').addEventListener('click', () => {
  const iconDom = document.querySelector('.icon');
  currentSize = parseInt(getComputedStyle(iconDom).getPropertyValue('--size'))
	iconDom.style.setProperty('--size', currentSize * 2 + 'px')
})

demo 结合 react 的 jsx 的话威力更大,可以感受一下这个作用域的意义。

<div class="icon" style={{ --size: count * 10 }}></div>

如果是有一定宽高比,那么引入一个 --ratio 即可。

储存完整值与部分值

CSS 渐变

:root {
  --gradient: linear-gradient(150deg, #235ad1, #23d1a8)
  --angle: 150deg;
}
.total {
  background-image: var(--gradient)
}
.angle {
  background-image: linear-gradient(var(--angle, 150deg), #235ad1, #23d1a8);
}
.angle:hover {
  --angle: 0deg;
}

demo

切换黑暗和明亮模式

:root {
  --text-color: #434343;
  --border-color: #d2d2d2;
  --main-bg-color: #fff;
  --action-bg-color: #f9f7f7;
}


.dark-mode {
  --text-color: #e9e9e9;
  --border-color: #434343;
  --main-bg-color: #434343;
  --action-bg-color: #363636;
}

demo

储存多个值

在多值属性的时候,如果只有部分改变其余部分保持一致的时候可以提取保持一致部分为变量。类似的有 rgba, hsl, background 等等任意多值属性, 用逗号隔开即可。

:root {
  --main-color: 35, 90, 209
}
.title {
  color: rgba(var(--main-color), 0.75)
}

与动画结合

可以很方便的复用animation

@keyframes breath {
  from {
    transform: scale(var(--scaleStart));
  }
  to {
    transform: scale(var(--scaleEnd));
  }
}

.walk {
  --scaleStart: 0.3;
  --scaleEnd: 1.7;
  animation: breath 2s alternate infinite;
}

.run {
  --scaleStart: 0.8;
  --scaleEnd: 1.2;
  animation: breath 0.5s alternate infinite;
}

demo

注意有个问题,类似下面的场景是没有动画的

.box {
  transform: translate(var(--offset, 0));
}
.box-1 {
  animation: offsetAnimation .3s alternate infinite;
}
@keyframes offsetAnimation {
  from {
    --offset: 0;
  }
  to {
    --offset: 100px;
  }
}

不过 chrome, ff,safari 现在支持属性的定义@property语法,在元素上注册自定义属性,可参考地址

@property --offset {
  syntax: "<length-percentage>";
  inherits: true;
  initial-value: 0;
}

demo