thumbnail

sass是一种css预编译语言,平时可能我们使用到的都是一些简单的sass语法,比如嵌套变量混入 这些语法,对函数的使用率很低,今天我们用一个下雪的背景作为例子,学习一下sass函数的用法。


创建DOM结构

既然是下雪的效果,那么肯定不可能只有一两片雪,是需要创建很多个 dom 元素的。

如果在 html 部分手动复制粘贴的话,不仅会多很多代码量,看上去也很难受。那么如何快速的创建多个类似的 dom 元素呢?

除了 CSS 和 HTML,我们还有 JavaScript。

基础DOM结构

首先,先把外层的父元素确定下来。

<div class="scss-snow-bg"></div>

然后将它铺满整个页面,并且添加一个背景色

html,
body {
  width: 100vw;
  height: 100vh;
}

.scss-snow-bg {
  width: 100%;
  height: 100%;
  background: radial-gradient(ellipse at bottom, #1b2735 0%, #090a0f 100%);
  overflow: hidden;
  filter: drop-shadow(0 0 10px white);
}

于是我们得到了一个 夜晚场景

通过js创建多个雪花元素

上面说了,雪花可能有很多片,这里我们假设有 两百片雪花,如果手动写 html 的话,就需要粘贴很多,那么更方便的肯定就是通过 JS 来创建了。

目前创建元素的方式一般有三种:

  • document.write():页面加载时执行会在页面末尾接着插入;而在页面加载完毕之后再执行则会清空页面所有内容再插入
  • element.innerHTML:会清空元素内部的所有内容再重新插入编辑的内容
  • document.createElement():只会在内存中创建一个元素对象,需要手动调用 element.appendChild 将该元素插入到目标元素中

如果我们只是需要在页面中插入一些新元素而不想影响页面其他内容,一般都是采用第三种方式。

const box = document.querySelector('.scss-snow-bg');

for(let i = 0; i < 200; i++) {
    let snow = document.createElement('div')
    snow.classList.add('snow')
    box.appendChild(snow)
}

将循环创建的 snow 节点都添加到该片段中,最后统一一次性插入到父元素。

const box = document.querySelector('.scss-snow-bg');

const fragment = document.createDocumentFragment();

for(let i = 0; i < 200; i++) {
    let snow = document.createElement('div')
    snow.classList.add('snow')
    fragment.appendChild(snow)
}

box.appendChild(fragment)

此时,我们就得到了一个具有两百个 div.snow 的父节点div.scss-snow-bg。

Sass相关语法

首先,我们先来复习一下这个效果中用到的 Sass 的 random 随机函数 和其他特性。

Random

该函数在 Sass 中被称为 数字函数,与 JS 中的 Math.random 函数作用类似,都是用来 创建一个随机数。没有参数时是直接创建 0 ~ 1 之间的随机数,并且一般会伴随着四五位小数;而传递参数 n 之后,则是 创建一个 1 ~ n 之间的随机数。

而与 Math.random 不同的是,Sass 的 random 函数在传递参数时 该参数值必须大于 1 且是正整数,不然会报错,并且结果也 不是 0 ~ n,而是 1 ~ n。

该函数生成的值可以通过 #{} 组合成一个字符串,或者通过与 有单位的值 进行计算得到一个 css 样式值。

Floor

该函数就与 JS 中的 Math.floor 基本一致了,都是 向下取整数值

当然 Sass 中还有很多数字相关的处理函数,有兴趣的同学可以查看官方文档。

@function

这个语法在 Sass 中也被称为 指令,可以配合 @return 实现自定义函数。与 JS 中的 function 和 return 关键字 差不多。

但是,Sass 中定义的函数必须有一个 直接可用的 返回值,而不像 JS 那样可以默认返回一个 undefined

动画

因为雪花肯定是白色的,而且为了定位方便,一般都采用绝对定位的方式来处理,所以此时我们先给 雪花 加上一个基础样式。

.snow {
  $total: 200;
  position: absolute;
  width: 10px;
  height: 10px;
  background: white;
  border-radius: 50%;
}

实现雪花的动画用到的肯定不止是从 1 开始的随机数就能满足的,需要实现一个 范围内随机数的 工具函数

所以先定义个范围内随机数的自定义函数 random_range

@function random_range($min, $max) {
  $rand: random();
  $random_range: $min + floor($rand * (($max - $min) + 1));
  @return $random_range;
}

其实这个函数的思路与 JS 生成范围内随机数的思路一致。

然后,就是 从 0 开始循环生成动画和定位部分:

  @for $i from 1 through $total {
    $random-x: random(1000000) * 0.0001vw;
    $random-offset: random_range(-100000, 100000) * 0.0001vw;
    $random-x-end: $random-x + $random-offset;
    $random-x-end-snow: $random-x + ($random-offset / 2);
    $random-snow-time: random_range(30000, 80000) / 100000;
    $random-snow-y: $random-snow-time * 100vh;
    $random-scale: random(10000) * 0.0001;
    $fall-duration: random_range(10, 30) * 1s;
    $fall-delay: random(30) * -1s;

    &:nth-child(#{$i}) {
      opacity: random(10000) * 0.0001;
      transform: translate($random-x, -10px) scale($random-scale);
      animation: fall-#{$i} $fall-duration $fall-delay linear infinite;
    }

    @keyframes fall-#{$i} {
      #{percentage($random-snow-time)} {
        transform: translate($random-x-end, $random-snow-y) scale($random-scale);
      }

      to {
        transform: translate($random-x-end-snow, 100vh) scale($random-scale);
      }
    }
  }

最后为每个雪花都定义了一个专属的动画 @keyframes fall-#{$i} ,也是让每片雪花的 动画、大小、透明度、动画运动路径都不一样了。

关于本文

文章转自掘金作者𝑴𝒊𝒚𝒖𝒆𝑭𝑬——《✨✨使用 Sass 函数制作一个落雪背景》

如果本文对你有所帮助,可以帮我点个赞或者请我喝杯奶茶~万分感谢🎉🎉🎉