✨✨使用 Sass 函数制作一个落雪背景

简介: ✨✨使用 Sass 函数制作一个落雪背景

开篇


周五继续在 codepan 寻找灵感的时候发现了一个使用 Sass 来完成的一个落雪效果,大致看了一下,是通过 Sass 的 random 函数配合其他函数来实现的,通过 random 定义多个不确定变量来实现各个元素之间的大小位置和动画效果


因为平时虽然也有用到过 Sass、less 之类的 CSS预编译语言,但是最常用的其实也就是 嵌套、变量、混入 这些语法,对函数的使用率很低,所以也趁机学习一下吧~


创建 DOM 结构


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

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


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


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


<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);
}


此时,就得到了一个 夜晚场景


image.png


下面,就是通过 JS 来创建 很多 子元素了。


JS 创建雪花


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


JS 创建元素的三种方式


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


  1. document.write():页面加载时执行会在页面末尾接着插入;而在页面加载完毕之后再执行则会清空页面所有内容再插入


  1. element.innerHTML:会清空元素内部的所有内容再重新插入编辑的内容


  1. 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)
}


但是,这样会造成页面重复渲染多次,十分影响性能和用户体验。那么此时我们可以通过 DocumentFragment 文档片段来优化。


将循环创建的 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%;
}


这里先定义了一个变量 $total,表示我们的雪花总数有两百个


实现雪花的动画用到的肯定不止是从 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-yoyo: $random-x + ($random-offset / 2);
    $random-yoyo-time: random_range(30000, 80000) / 100000;
    $random-yoyo-y: $random-yoyo-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-yoyo-time)} {
        transform: translate($random-x-end, $random-yoyo-y) scale($random-scale);
      }
      to {
        transform: translate($random-x-end-yoyo, 100vh) scale($random-scale);
      }
    }
  }


这里为什么随机数需要取 这么大的范围,最后又乘一个很小的小数?

个人认为也是为了 减小随机数会生成的多位小数造成的显示误差


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


image.png


Markup:

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


Style:

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);
}
@function random_range($min, $max) {
  $rand: random();
  $random_range: $min + floor($rand * (($max - $min) + 1));
  @return $random_range;
}
.snow {
  $total: 200;
  position: absolute;
  width: 10px;
  height: 10px;
  background: white;
  border-radius: 50%;
  @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-yoyo: $random-x + ($random-offset / 2);
    $random-yoyo-time: random_range(30000, 80000) / 100000;
    $random-yoyo-y: $random-yoyo-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-yoyo-time)} {
        transform: translate($random-x-end, $random-yoyo-y) scale($random-scale);
      }
      to {
        transform: translate($random-x-end-yoyo, 100vh) scale($random-scale);
      }
    }
  }
}


Script:

const app = document.querySelector('.scss-snow-bg');
const contents = new Array(200).fill(0);
const fragment = document.createDocumentFragment();
contents.forEach(() => {
  let snow = document.createElement('div')
  snow.classList.add('snow')
  fragment.appendChild(snow)
})
app.appendChild(fragment)


最后


虽然效果看起来比较简单,但是相关的一些语法和函数在平时也确实很少泳道,偶尔看看大佬们实现的一些动画效果,对自己的启发和技术积累也有很大帮助。


目录
相关文章
|
2天前
|
前端开发 容器
《CSS 简易速速上手小册》第2章:CSS 布局与定位(2024 最新版)
《CSS 简易速速上手小册》第2章:CSS 布局与定位(2024 最新版)
22 2
|
7月前
vscode编辑器使用拓展插件background添加背景图片改变外观
vscode编辑器使用拓展插件background添加背景图片改变外观
105 0
|
9月前
|
前端开发
如何使用css制作一个三角形?
如何使用css制作一个三角形?
49 0
|
11月前
vue3_制作一个在线修改svg颜色功能
vue3_制作一个在线修改svg颜色功能
167 1
|
12月前
|
程序员 uml
Markdown骚操作|字体颜色、字体背景、流程图一网打尽【建议收藏】
Markdown骚操作|字体颜色、字体背景、流程图一网打尽【建议收藏】
|
存储 前端开发 JavaScript
sass笔记 - 实战中颜色的玩法总结
这篇文章是针对自己封装UI组件库的读者的,旨在为项目提供通用的颜色方案本文需要读者拥有CSS、SASS/SCSS相关基础知识。
154 0
sass笔记 - 实战中颜色的玩法总结
|
前端开发
5 分钟一览 CSS 颜色表示方法和专业用法
5 分钟一览 CSS 颜色表示方法和专业用法
|
前端开发 JavaScript
详解在 vaw-layouts 中通过 sass 实现动态换肤功能 (一)
以往的前端开发中,css 一直不能称之为一种编程语言,虽然在 css3中增加了几个变量和函数,但是实现的功能还是比较有限。后来出现了几个css预处理器,比较常用的有:sass、less 、stylus。有了他们,我们可以对css进行一些简单的编程。如果您对他们还不了解,可以查看一下他们的官网学习一下,vaw-layouts项目中使用的的预处理器是sass,因此本文也是基于sass进行讲解实现动态换肤的功能。
详解在 vaw-layouts 中通过 sass 实现动态换肤功能 (一)
|
前端开发
图标库的正确使用方式
今天来教大家在实际开发中引入图标库
442 2
图标库的正确使用方式
|
前端开发
css中定位和背景的基本使用方式
通过本章认识css中定位和背景的基本使用方式。
111 0