阅读 3725

双11小黑盒很炫酷?咱们用CSS变量来改进一下!

前言

刚过去的双11大家都去哪些网站购物了呢?不管去哪个网站,估计都少不了天猫吧,在逛天猫时发现了这样一种有趣的现象:

虽然说这种效果还比较常见,但有一个细节与众不同,比如说咱们先来看一个普通的 header 随窗口滚动而渐隐渐现的效果:

对比一下发现哪里不同了么,普通版的是一开始完全透明,随着窗口的滚动而慢慢显示出来,靠的是控制opacity透明度属性来实现的。

而小黑盒那版是一开始就有一个渐变色,渐变到接近半透明,这种方式看起来更加的优雅,但看起来只是一开始进入页面还没滚动的时候带着很漂亮的渐变色,一滚动的时候行为又和以前靠透明度的时候差不多。

咱们要改进的就是用滚动的距离来控制background-position,随着窗口的滚动,会慢慢改变渐变色渐变的程度而控制显隐效果。

样式

首先咱们先把header的样式写出来:

header {
      /* 设置一个控制背景色位置的CSS变量,方便JS控制 */
      --position: 100;

      /* 居中靠下显示子元素 */
      display: grid;
      place-items: end center;

      /* 设置为固定定位 */
      position: fixed;

      /* 距离上边左边为0 */
      top: 0;
      left: 0;

      /* 宽度铺满屏幕 */
      width: 100%;

      /* 给个合适的高度 */
      height: 40px;

      /* 白色字体 */
      color: white;

      /* 字体大小 */
      font-size: 16px;

      /* 让字体细一点 */
      font-weight: 100;

      /* 增加下内变局,防止文字过于靠下 */
      padding-bottom: 10px;

      /* 设置过渡效果 */
      transition: background-position .2s;

      /* 黑色渐变背景 */
      background: linear-gradient(black, rgba(148, 88, 88, 0.3) 80%, rgba(0, 0, 0, 0)) 0 calc(var(--position) * 1%) / 100% 300%;
    }
复制代码

运行结果:

可以看到我们在header里面设置了一条CSS变量,如果不太清楚什么是CSS变量的话请点击这里,这里还用到了 gird 来进行居中,当然并不是完完全全的居中,而是稍稍偏下了一点,因为我看天猫的小黑盒就是做的偏下居中。

整体实现

然后咱们开始写 JS 代码了,因为纯 CSS 的话还是无法获取屏幕的滚动距离,但是为了能够更方便的进行双方交互,我们还是采用了CSS变量,因为CSS变量带来的提升绝不仅仅是节约点 CSS 代码,以及降低 CSS 开发和维护成本这点作用。

更重要的是,把组件中众多的交互开发从原来的JS转移到了CSS代码中,让组件代码更简洁,同时让视觉表现实现更加灵活了。 ——张鑫旭

CSS变量具体能为我们带来哪些好处,可以参考张鑫旭的博客:

《CSS变量对JS交互组件开发带来的提升与变革》

来看一下CSS变量是怎么与 JS 进行交互的:

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no">
  <title>属于自己的渐变小黑盒</title>
  <style>
    /* 清除默认样式 */
    * { padding: 0; margin: 0 }

    header {
      /* 设置一个控制背景色位置的CSS变量,方便JS控制 */
      --position: 100;

      /* 居中靠下显示子元素 */
      display: grid;
      place-items: end center;

      /* 设置为固定定位 */
      position: fixed;

      /* 距离上边左边为0 */
      top: 0;
      left: 0;

      /* 宽度铺满屏幕 */
      width: 100%;

      /* 给个合适的高度 */
      height: 40px;

      /* 白色字体 */
      color: white;

      /* 字体大小 */
      font-size: 16px;

      /* 让字体细一点 */
      font-weight: 100;

      /* 增加下内变局,防止文字过于靠下 */
      padding-bottom: 10px;

      /* 设置过渡效果 */
      transition: background-position .2s;

      /* 黑色渐变背景 */
      background: linear-gradient(black, rgba(148, 88, 88, 0.3) 80%, rgba(0, 0, 0, 0)) 0 calc(var(--position) * 1%) / 100% 300%;
    }

    main {
      /* 给个合适的高度 */
      height: 1000px;
    }
  </style>
</head>
<body>
  <header>咱们自己的小黑盒</header>
  <main></main>

  <script>
    // 获取header
    const header = document.getElementsByTagName('header')[0]

    addEventListener('scroll', () => {
      // 获取偏移值
      const top = document.documentElement.scrollTop

      // 设置一个合适的范围
      if (top <= 200) {
        // 令header的渐变色位置变成计算后的渐变位置
        header.style.setProperty('--position', 100 - Math.min(100, top))
      } else {
        // 在移动一定范围后令其完全不透明
        header.style.setProperty('--position', 0)
      }
    })
  </script>
</body>
</html>
复制代码

运行结果:

想象一下如果不用CSS变量的话会变成什么样:

header.style.backgroundPosition = '0 ' + 100 - Math.min(100, top) + '%'
复制代码

虽然看起来好像没啥的,但当要控制的属性较多时这将会是一种灾难,而且这种方式要时刻都带着 CSS 单位,像 px、%、rem 这些,为我们增加了不必要的心智负担,而且也拖慢了程序的运行效率。

用了CSS变量之后都不用带单位了,直接赋值一个数字即可,那么为什么可以不带单位呢?答案就在 calc 函数上:

calc(var(--position) * 1%)

记住在这里可不能再用 JS 的思维来写 calc 函数了,在 JS 里我们用的是+,因为这代表了字符串拼接,而在这里数字乘以百分之一,就会变成具体的百分数,同理如果你需要的是其他单位的话可以根据具体需求进行灵活修改:

calc(var(--position) * 1px)

⚠️注意 px 前面那个1很重要,不能省略掉!

而且也不是必须要写1,还可以根据具体的需求按倍数来:

calc(var(--position) * 6.6rem)

扩展

其实从代码和我们日常生活中见到的效果可以得知,基本上滚动一段距离后header的透明度就固定住了不会再发生变化,浪费了监听 onscroll 事件。但又不能取消监听,因为不知道用户何时会再滑到顶部去,但这种情况却非常适合做另一种效果:

我忘记了这种效果叫啥来着,总之就是随着用户滚动页面的距离而在顶部显示一个类似于进度条之类的东西,方便用户得知自己处在网页中大概什么样的一种位置,来看代码:

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no">
  <title>属于自己的渐变小黑盒</title>
  <style>
    /* 清除默认样式 */
    * { padding: 0; margin: 0 }

    header {
      /* 设置一个控制位置的CSS变量,方便JS控制 */
      --position: 0;

      /* 设置为固定定位 */
      position: fixed;

      /* 距离上边左边为0 */
      top: 0;
      left: 0;

      /* 宽度铺满屏幕 */
      width: 100%;

      /* 给个合适的高度 */
      height: 10px;

      /* 设置过渡效果 */
      transition: transform .1s;

      /* 渐变背景 */
      background: linear-gradient(to right,#4481eb,#04befe);

      /* 设置形变效果 */
      transform: scaleX(var(--position));

      /* 设置变形参照点 */
      transform-origin: left;
    }

    main {
      /* 给个合适的高度 */
      height: 10000px;

      /* 渐变背景 */
      background: linear-gradient(#30cfd0,#330867)
    }
  </style>
</head>
<body>
  <header></header>
  <main></main>

  <script>
    // 获取header
    const header = document.getElementsByTagName('header')[0]

    addEventListener('scroll', () => {
      // 获取偏移值
      const top = document.documentElement.scrollTop

      // 获取页面总高度
      const height = document.documentElement.scrollHeight

      // 设置CSS变量
      header.style.setProperty('--position', top / (height - document.documentElement.clientHeight))
    })
  </script>
</body>
</html>
复制代码

本文首发于微信公众号:《前端学不动》

往期精彩文章

文章分类
前端
文章标签