css变量——绝对让你相见恨晚的原生css特性

705 阅读3分钟

使用css变量完美的契合了最近的一个业务需求,初识css变量,相见恨晚呐!!!

业务背景

业务需求是这样的,根据用户测评的结果进行展示,测评报告中编写如下组件:

业务组件1.png

因为测评结果的不同,整个组件的主题颜色是不同的,下面是另一种测评结果的样式:

业务组件2.png

需求分析

首先这个肯定是抽取一个组件,组件根据props里的数据进行渲染,这个组件不只是单纯的数据展示,还要根据props里具有标示意义的变量决定整个组件的渲染样式——其实基本结构完全一样,说白了就是主体颜色等一些css属性不同。

解决方案

第一反应

这不简单,vue项目的话直接在模版中用:style或者说针对不同的主题编写不同的类,然后通过变量控制渲染什么style或者什么class即可。我一开始也是这么做的,但是随着编码的进行,发现每个div只要是用到主题色的,都需要写渲染的条件判断。代码相当冗余且丑陋。

终极方案

使用css原生变量,css变量也叫css自定义属性,它是一种将css与js相连接的技术方案,绝对不是与less或者sass等css预处理器同级的工具。

css变量

基础

阮一峰经典总结

我再挑一些感觉常用到的点说一说:

首先是对css变量的理解,说白了css变量就是自定义属性,我们在css里写margin: 0 auto;这就是一个css属性,我们写以--开头的属性名,如--main-color: #4d4e53;这就是一个自定义属性,只是说它没有默认含义(渲染效果)罢了。

变量声明

如下在body选择器里声明了两个css变量(我还是喜欢叫它css自定义属性):

body {
  --foo: #7F583F;
  --bar: #F7EFD2;
}

var()函数使用自定义属性值

var(变量名)来使用css自定义属性的属性值:

a {
  color: var(--foo);
  text-decoration-color: var(--bar);
}

与js联系(核心)

js中通过dom.style.setProperty(css自定义属性名, 属性值)可以修改dom中定义的css自定义属性值(具体例子看下面)

需求实战

我们复用css自定义属性时,相当于提取了公共样式,就像我的需求,很多地方都用到了主题颜色属性,我首先在组件的根元素container里定义一个自定义属性:

<style lang="less" scoped>
.container {
    --theme-color: ''; // 定义自定义属性--theme-color
    ...
    .module-box {
        background-color: var(--theme-color); // 需要根据主题进行切换的地方都使用--theme-color
        ...
    }
}
</style>

js中根据组件的props的主题控制变量来控制自定义属性值:

<script setup lang="ts">
import {defineProps, onMounted, ref} from 'vue';
const props = defineProps<{detailInfo: any}>(); // 接收props属性
const containerElm = ref<null | HTMLElement>(null); // 获取定义了css变量的dom元素
onMounted(() => {
    containerElm!.value!.style?.setProperty('--theme-color', `${props.detailInfo.color}`); // 用dom.style.setProperty(css自定义属性名, 属性值)的方式给自定义属性赋值
});
</script>

plus

vue中直接可以在<script>中用v-bind去绑定js中的变量,其实本质也是对css自定义属性的语法糖:Vue:css中的v-bind

总结

一个关于css变量(css自定义属性)的误区就是拿它与less、sass等css预处理器去做比较,我感觉完全不是一类东西,预处理器是在纯css领域协助开发的,而css变量沟通了css与js,准确的说是让js具有批量修改css的能力(一旦自定义属性值改变,所有使用的地方样式都发生修改)。

关于前端的一键换肤需求,我没做过,不确定有没有其他的技术方案,但现在想想,利用css变量去实现,只能说轻而易举。