CSS中的变量&函数&伪类,让开发事半功倍

1,733 阅读5分钟

前言

都说能用 CSS 尽量不要用 JS,一些合适的 CSS 甚至能让我们少写很多 JS,实现起来也更加简单。本文主要分享些好用的 CSS 技巧,接下来你将学到CSS变量的规则,函数与伪类在实践中的应用。

变量

声明规则

在声明时,变量名前需要加 --,以表示为 CSS 变量。它和其他正常的属性没有太大区别,它的值可以是任何正常属性的值。所以 CSS 变量又叫做"CSS 自定义属性"。

body {
  --main-color: #4d4e53;
  --main-bg: rgb(255, 255, 255);
  --logo-border-color: rebeccapurple;

  --header-height: 68px;
  --Header-height: 70px;
  --content-padding: 10px 20px;

  --base-line-height: 1.428571429;
  --transition-duration: .35s;
  --external-link: "external link";
  --margin-top: calc(2vh + 20px);
}

需要注意的是变量名严格区分大小写,上面--header-height--Header-height 为两个不同变量。

使用变量

读取变量使用 var() 函数,且在定义变量时也可以使用该函数:

div {
  --main-color: #4d4e53;
  --color: var(--main-color);
  color: var(--color);
}

var() 函数还有第二个参数,该参数表示默认值,即变量不存在时,则使用默认值:

div {
  color: var(--main-color, #7F583F);
}

第二个参数内部不处理逗号和空格,会把它们作为参数整体:

div {
  font-family: var(--font-stack, "Roboto", "Helvetica");
  padding: var(--content-padding, 20px 10 15px);
}

作用域

CSS 变量也有它自己的作用域,就像 JS 查找变量一样,首先查询自己的作用域,其次再逐层往上寻找。

:root {
  --color: blue;
}
div {
  --color: red;
}
.box {
  --color: green;
}
* { 
  color: var(--color);
}
<div class="box">我是绿色</div>
<div>我是红色</div>
<span>我是蓝色</span>

虽然上面选择器使用的变量名是同样,但读取到值根据作用域来查找,所以每个元素的颜色也会不同。一般全局变量会放在 :root 中,以便任何选择器都能读取到。

JS 操作

在 JS 中提供了操作 CSS 变量的方法,这使得 CSS 变量可以根据不同的场景进行变化,更加的灵活。这些方法挂载在 Dom 的 style 属性上。

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

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

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

函数

calc()

calc() 可以说是开发中最常接触到的 CSS 函数,它主要用于动态计算 CSS 长度值。支持 + - * / 运算符,运算符左右必须有空格。

div {
  width: calc(200px - -10%);
}

calc() 还能搭配 CSS 变量一起使用:

div {
  --w: 20px;
  width: calc(200px - var(--w));
}

除此之外还有一种应用场景,当 CSS 变量是一个纯数字时,可以使用该函数转为 CSS 长度单位:

div {
  --w: 20;
  width: calc(var(--w) * 1px);
  height: calc(var(--w) * 5px);
}

attr()

attr() 用于获取选择元素的某个属性值,并用于其样式,但目前支持的仅有伪元素的 content 属性。

<p data-unit="km">89</p>
p[data-unit] {
  font-size: 20px;
  color: #333;
}
p[data-unit]::after {
  content: attr(data-unit);
  color: #999;
}

上面的应用场景好处在于,将文字聚焦到 html 中,维护起来可以一目了然,不至于从 html 再跳到 css 去修改伪元素的 content。

cubic-bezier()

cubic-bezier() 定义贝塞尔曲线,可用于 animation-timing-functiontransition-timing-function 属性。一般场景下都会使用 css 自带的 ease ease-inease-out 等动画曲线,贝塞尔曲线可以根据需求自定义不同的动画速度曲线。比如定义一个带有回弹效果的动画:

div {
  transition: all 1s;
  transition-timing-function: cubic-bezier(.72,.67,.3,1.18);
}

为了更好的调试出想要的效果,有两种方法:

第一种,在浏览器的控制台中,点击贝塞尔曲线的小图标调出调试面板,拖拽两个控制点,可以实施预览动画效果。

第二种,在线生成贝塞尔曲线:

cubic-bezier.com

drop-shadow()

drop-shadow() 函数将阴影效果应用于输入图像。开发中常用 box-shadow 来设置元素阴影,还有一种是 CSS3 提供的 drop-shadow() 阴影滤镜。它对比 box-shadow 的好处是能投影出不规则阴影。

<div class="box1">box-shadow</div>
<div class="box2">drop-shadow</div>
.box1{
  box-shadow: 0 0 6px #ccc;
}
.box2{
  filter: drop-shadow(0 0 6px #ccc);
}

可以看到使用 box-shadow 的元素,在小箭头处是没有阴影处理的,它只是基于盒子做投影。而 drop-shadow 就像是真实的阴影,元素是什么形状,阴影就是什么形状。

repeat()

repeat() 用于 grid 布局。当使用 grid-template-columns 定义相同单位的列会比较冗余,这时使用 repeat() 可以简化写法。

.container{
  display: grid;
  justify-content: space-between;
  grid-template-columns: 150px 100px 150px 100px 150px 100px;
  /* 简化写法 */
  grid-template-columns: repeat(3, 150px 100px);
}

在不确定每行的个数时,使用 auto-fill 可以让 gird 自动计算,实现列表最后一行的左对齐。

<div class="container">
  <div class="item"></div>
  <div class="item"></div>
  <div class="item"></div>
  <div class="item"></div>
  <div class="item"></div>
  <div class="item"></div>
</div>
.container{
  --w: 150px;
  display: grid;
  justify-content: space-between;
  grid-template-columns: repeat(auto-fill, var(--w));
  grid-gap: 10px;
}
.item{
  width: var(--w);
  height: 120px;
  background-color: lightskyblue;
}

伪类

:not

:not 匹配不符合一组选择器的元素。例如一个场景,每个列表项需要添加下边框线,一般最后一项是不需要的。通常我们会为每一项都设置下边框线,再单独设置最后一项的 border-bottom 为 0。使用 :not 也可以实现。

.item{
  width: 200px;
  height: 100px;
  padding-bottom: 10px;
}
.item:not(:last-child) {
  border-bottom: 1px solid #ccc;
}

上面表示除了最后一项,其他都加上 border-bottom

:target

:target 代表一个唯一的页面元素,其 id 与当前 URL 片段匹配。比如,地址为 loacalhost:3000#red,则选择中ID属性值为red的元素。或许可以应用到网页换肤功能中。

div {
  display: inline-block;
  width: 200px;
  height: 200px;
}
#red:target {
  background: lightpink;
}

#blue:target {
  background: lightblue;
}
<body>
  <div id="red">
    <span>红色</span>
  </div>
  <div id="blue">
    <span>蓝色</span>
  </div>
  <p>
    <a href="#red">红色</a>
    <a href="#blue">蓝色</a>
  </p>
</body>

:empty

:empty 匹配没有子元素的元素。有时候列表的外层会包一层盒子,设置 padding 边距。当列表无数据返回时,外层盒子的 padding 会占用空间,使用 :empty 匹配无子元素时隐藏盒子,解决占用位置的问题。

.wrapper{
  padding: 10px;
}
.wrapper:emtry{
  display: none;
}

参考资料