变量
在 CSS 3 中,引入了变量机制,变量这个东西我们在 JS 中已经学习过,在 CSS 中差不多,基本也就是预设一个值,下次我们想用这个值的时候就可以直接引用变量,而不用在重新书写一遍,这样不管是从语义化还是我们书写代码的方便性上都要更胜一筹。
在 CSS 3 中,变量名以两个短横线开头。
css
.box {
--bgColor: red;
height: 100px;
width: 100px;
background-color: var(--bgColor);
}
在这个例子中,定义了一个变量名为 --bgColor,我们可以通过 var() 函数去使用这个变量。在 CSS 中,并没有数据类型这些概念,你引用变量相当于就是直接把定义变量时后面的属性值直接拿过来用。
在 CSS 中,属性名其实没有过多的限制,哪怕写中文,数字这些他都认,甚至是短横线本身也可以作为变量名,非常自由,但是对于一些带有含义的特殊字符我们需要加上转义字符才能使用,一般我们不推荐这么干,因为很麻烦。
实际上,在 JS 中你写中文变量名他也认。
实际上,在 var 函数中,我们是可以传入两个值的,第一个值就是我们要解析的变量,第二个值就是后备 CSS 属性,也就是当第一个变量不存在的时候才会使用后备 CSS 属性,注意,是不存在的时候才会使用后备 CSS 属性,只要第一个变量解析成功,哪怕你传递的是一个完全错误的数据,也会使用变量的值。
css
.box {
--bgColor: red;
height: 100px;
width: 100px;
background-color: var(--bgColor, green);/*不会使用默认值*/
}
.box {
--bgColor: 20px;
height: 100px;
width: 100px;
background-color: var(--bgColor, green);/*哪怕传递的是一个完全错误的属性,也不会使用默认值*/
}
.box {
height: 100px;
width: 100px;
background-color: var(--bgColor, green);/*在这种情况下,找不到到--bgColor,才会使用默认值*/
}其实这个也很好理解,毕竟 var 本身只是一个函数,这个函数的功能本身就是解析变量,它并不知道自己会被用在哪个属性上去,所以也就不可能根据属性的特点去进行逐个判断。
注意和 filter 函数做区分,filter 函数并不是真正意义上的 CSS 函数,CSS 函数是在任何情况下都可以使用的,但是 filter 函数只能在 filter 属性中可以使用,所以读者会看到 filter 函数多个参数是不需要逗号隔开的,而是直接用空格分割,但是 CSS 函数传入的多个参数是用逗号隔开的。
这里我们利用 CSS 变量实现一个可配置的渐变色
css
.box {
--direction: to right;
--color1: skyblue;
--color2: aqua;
height: 100px;
width: 100px;
background-image: linear-gradient(var(--direction), var(--color1) 50%, var(--color2) 100%);
}
这样写之后,我们只需要改变变量的值,就可以快速修改渐变的颜色和方向。
CSS 变量,之所以称为变量,就是可以被重复赋值,后赋值的变量会直接覆盖前面的变量,实际上这和 CSS 的特点有关,后书写的属性是会覆盖前面属性的。
css
.box {
width: 100px;
height: 100px;
--color: red;
background-color: var(--color);
/*背景色会被修改为蓝色,而非红色,因为后面的--color覆盖了前面的--color,所以解析的时候会解析为蓝色*/
--color: skyblue;
color: var(--color);
}CSS 变量也是有作用域的,我们定义一个变量一定是在某个元素内部定义的,只要是在元素 A 内部定义的变量,在元素 A 的所有后代元素中均可访问。
css
.box {
width: 100px;
height: 100px;
--color: red;
}
.boxChild {
width: 50px;
height: 50px;
background-color: var(--color);
/*这是可以访问到的,因为.boxChild为.box的子元素*/
}基于这个原理,如果我们要写一些全局变量,就可以直接写在 html 元素中,当然也可以使用 :root 选择器。
在行见样式中也可以直接设置和使用 CSS 变量,这一点在某些情况下可以为我们的 JS 提供一些方便
注意下面的问题:
css
.box {
width: 100px;
height: 100px;
--size: 20;
font-size:var(--size)px;/*这样写是不会生效的*/
}注意,上面的写法是不会生效的,因为 CSS 属性值虽然可以解析函数,但本质上也只能解析函数,这里其实就直接涉及到计算了,也就是要用 var(--size) 的解析结果拼接上 px 这个东西,这是不行的,当然,我们可以使用 calc() 函数实现这个功能,这个东西放到后面来介绍。
我们可以使用 CSS 变量完成一些很常见的操作,比如典型的切换主题
css
<!DOCTYPE html>
<html lang="cmn-hans">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Document</title>
<style>
* {
margin: 0;
}
.theme1 {
--color: skyblue;
--bgColor: pink;
}
.theme2 {
--color: aqua;
--bgColor: purple;
}
.theme3 {
--color: green;
--bgColor: white;
}
.box {
width: 100px;
height: 100px;
color: var(--color);
background-color: var(--bgColor);
}
</style>
</head>
<body>
<div class="box theme1">
asdfasfa
</div>
<button>切换主题</button>
</body>
</html>
<script>
const btn = document.getElementsByTagName('button')[0];
const box = document.querySelector(".box");
let currentTheme = 1;
btn.addEventListener("click", function () {
box.classList.remove("theme" + currentTheme);
currentTheme++;
if (currentTheme > 3) {
currentTheme = 1;
}
box.classList.add("theme" + currentTheme);
});
</script>我们可以使用一个类选择器用来保存变量,当我们需要修改变量值的时候,只需要切换类选择器即可,不需要再用 JS 一个一个设置。
CSS 变量本质上还是一个属性,所以我们完全可以用 JS 去动态定义和修改 CSS 变量,有时候使用 JS 修改变量会比使用 JS 直接修改属性的可读性更强,也会带来一些便捷
函数
CSS 还给我们提供了很多函数,在前面我们其实已经接触过非常多的 CSS 3 函数了,例如 filter 中的各种滤镜函数,例如 transform 中的各种函数,例如 grid 布局中的 repeat 函数,这些都是 CSS 3 提供的函数,但是我们上面的函数基本都只在一个或者某几个属性中生效,这里我们介绍的 CSS 3 函数更为通用。
首先,上面介绍的 var() 函数就是一个 CSS 3 提供的函数,这个函数用于解析变量,这里不再赘述。
这里只能介绍部分常见函数,如果读者对 CSS 函数感兴趣,参见 CSS 参考 - CSS:层叠样式表 | MDN
首先是 calc() 函数,这个函数用于计算表达式,但是这个表达式需要带上单位,这一点尤其注意
css
.box {
width: 100px;
height: calc(100px + 100px);
background-color: aqua;
}
这里就实现了一个 100*200 的盒子,可以看到 calc(100px + 100px) 返回的其实就是 200px。
实际上
calc函数是可以不带单位的,如果写calc(100 + 100)得到的是200,但是形如height:200这种是典型的错误语法,所以在这里不能直接写calc(100 + 100)
关于 calc 函数需要注意一个细节,就是符号左右都必须加上空格
css
.box {
width: 100px;
height: calc(200px-100px);/*这是典型的错误语法,因为减号左右缺少空格,正确写法为:calc(200px - 100px)*/
background-color: aqua;
}calc 函数可以实现多个数据的四则运算,但在加减运算的过程中,单位是必须要统一的,并且 calc 函数可以用于任何可以计算的单位,包括时间,像素这些都可以使用 calc 计算,注意带上统一的单位即可。
这里注意相对单位的问题,我们可以设置
height:calc(100% - 100px),这里是没问题的,这是由于100%是一个相对单位,而相对单位本质上是一个绝对单位,也就是说它本质上还是像素值,只不过这里使用了相对单位来书写,所以可以进行减法。包括 em,rem 这些单位都是没有问题的。
而对于乘除操作,则更为简单,举个例子,calc(10px * 10px) 这个东西其实是没有含义的,我们要表达的应该是 10 个 10 像素,而不是 10 像素乘以 10 像素,能理解这个意思吧,这个 10 个 10像素,第一个 10 实际上是没有单位的,也就是说我们应该写作 calc(10 * 10px),这样才是正确的写法。
这也可以验证
calc函数实际上是可以用于数学计算的,width:calc(calc(100 + 100) * 1px),我这里先使用calc(100 + 100),得到 200,也就相当于width:calc(200 * 1px),得到width:200px。
当然,对于乘法而言,
calc(10 * 10px)和calc(10px * 10)是等价的,反正就是一个有单位一个没单位即可
对于除法而言,本质是一样的,除法的本质就是把一个东西分成几份,如果我们写作 calc(100px / 10px),相当于把 100 像素分成 10 像素份,这是不合逻辑的,我们应该写作 calc(100px / 10) 把 100 像素分成 10 份,这才符合逻辑,最后可以得到 10 像素。
实际上读者不需要记那么多规则,只要保证单位统一且有效即可
calc 可以帮助我们实现非常多的效果,例如我们的圣杯布局,如果使用浮动的方式去实现,在 CSS 2 中我们要采用两个定宽盒子分别左右浮动,然后中间的盒子设置左右 margin 的方式来实现。而有了 calc 函数,我们完全可以让中间的盒子宽度为 calc(100% - value),其中 value 为左右两个定宽盒子的宽度之和。
包括像元素的水平垂直居中,也可以通过 calc 的计算来实现。calc 的应用场景非常广泛,需要在开发的过程中自行探索。
calc 函数是本节最重要的函数,应用场景相当广泛,一定掌握。
接下来介绍几个其他函数,首先是 attr 函数,该函数可以拿到元素身上的属性
css
a {
--href: attr(href);
}
a::after {
content: "(" var(--href)")";
}
此时我们的 a 元素后面就会自带该属性,当然,直接在伪元素中使用 attr(href) 也是可以的。
接下来是 min() 和 max() 方法,这两个方法可以返回一堆数据的最小值或最大值,当然也要注意单位的统一。
最后要介绍的是 clamp() 函数,clamp(n,min,max) 可以认为是对 n 的值做一个限制,如果 n 的值在 min 和 max 之间就是用 n,如果 n 小于 min 就是用 min,大于 max 就使用 max。