2

CSS 快速实现烟花绽放🎆

 2 years ago
source link: https://segmentfault.com/a/1190000040635362
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

最近项目上需要做一个烟花动画,要求是随机大小,不同地方出现,先看效果

一、选择合适的动画

什么样的场景决定使用什么样的动画。比如一些比较轻量、装饰性的动画,CSS 动画就足够了,而一些对动画要求比较高的运营活动,创意小游戏等,JS 动画肯定是首选,必要情况下还需要借助一些图形库,比如 Pixi.js

其次,还需要从学习成本考虑。一般而言,CSS 使用起来更容易,上手成本更低,局部需要稍微复杂的动效可以直接参考已有的库,例如 Animate.css。JS 可能就复杂一些了,原生 JS 还好,如果是其他图形库,又需要面对完全不一样的 api,都是学习成本。

最后,也需要考虑工程化。例如 lottie-web 本身就已经很大了(532k,压缩后150k,gzip后也有43k),另外设计导出的动画 json 文件也会很大,仅仅是为了一个动画而引入整个 lottie 就有些不划算了,应该换其他方式。

综合考虑,烟花动画可以采用 CSS 实现

二、单个烟花的实现

这里我们可以采取序列帧的方式来实现。比如我会要求设计师导出一组序列帧图片,像这样的

然后把这些图片按照顺序合在一张图片上,可以使用一些在线生成工具,例如 sprite-generator,就得到了这样的图片

接下来,只需要利用 CSS 动画函数中的 steps() 功能符,逐帧动画就完成了

假设有如下 HTML 结构

<div class="fireworks"></div>

CSS 实现为

.fireworks {
    position: absolute;
    width: 150px;
    height: 150px;
    background: url('https://imgservices-1252317822.image.myqcloud.com/image/081320210201435/e9951400.png') right top no-repeat;
    background-size: auto 150px;
    animation: fireworks 1s steps(24) infinite;
}
@keyframes fireworks {
    to {
        background-position: 100%;
    }
}

Kapture 2021-08-21 at 10.49.07

三、随机位置的烟花

现在烟花每次出现的位置都是相同的,太有规律显得不那么自然,那么如何实现一会在这里一会在那里的效果呢?这里可以再添加一个关键帧,随便改几个位置(不一定需要真的随机,只需要看着不那么规律即可)

@keyframes random {
    25% {
        transform: translate(200%, 50%);
    }
    50% {
        transform: translate(80%, 80%);
    }
    75% {
        transform: translate(20%, 60%);
    }
}

然后把两个动画组合起来

.fireworks {
    /* 其他 */
    animation: fireworks 1s steps(24) infinite, random 4s infinite;
}

Kapture 2021-08-21 at 11.09.14

是不是很奇怪的动画?原因是在改变位置的时候也是平滑过渡的,所以这个地方也需要加上 steps(),注意这里只需要 steps(1)就可以了,表示这个过程中直接跳到指定关键帧就结束了,不会自动在途中创建其他帧

.fireworks {
    /* 其他 */
    animation: fireworks 1s steps(24) infinite, random 4s steps(1) infinite;
}

Kapture 2021-08-21 at 11.17.22

这样是不是自然多了?

四、随机大小的烟花

随机位置有了,现在再加点大小变化,只需要在位置变化的基础上加上 scale 就可以了

@keyframes random {
    25% {
        transform: translate(200%, 50%) scale(0.8);
    }
    50% {
        transform: translate(80%, 80%) scale(1.2);
    }
    75% {
        transform: translate(20%, 60%) scale(0.65);
    }
}

Kapture 2021-08-21 at 11.44.26

这样一个随机位置、随机大小的烟花就完成了

五、多个烟花随机绽放

单个烟花始终还是有些单调,现在多加几个,由于现在单个烟花会出现 4 个不同的位置,所以并不需要太多的 HTML 结构,每个给一个不同的位置

<div class="fireworks" style="left: 15%; top: 5%;"></div>
<div class="fireworks" style="right: 30%; top: 13%;"></div>
<div class="fireworks" style="left: 5%; top: 23%;"></div>
<div class="fireworks" style="right: 45%; top: 8%;"></div>

Kapture 2021-08-21 at 11.55.20

4个一起出现,太整齐了,所以需要添加一些延时 animation-delay 错开出现的时间

<div class="fireworks" style="left: 15%; top: 5%;"></div>
<div class="fireworks" style="right: 30%; top: 13%; animation-delay: -0.4s;"></div>
<div class="fireworks" style="left: 5%; top: 23%; animation-delay: -1.7s;"></div>
<div class="fireworks" style="right: 45%; top: 8%; animation-delay: -3.1s;"></div>

这样就得到了文章开头的效果了

Kapture 2021-08-20 at 23.17.31

完整代码可访问 CSS fireworks (codepen.io)

六、绚丽多彩的烟花

设计同学觉得白色有些太单调,想换个颜色,比如黄色?由于我们已经做成了序列帧图片,不可能再生成一套黄色烟花的图片,那么问题来了,如何通过 CSS 更换颜色呢?

这里就又不得不借助一下 CSS Mask 了,关于 Mask 之前的文章介绍过很多实用的案例,这里就不多介绍了,如果还不熟悉 mask,可以参考这一篇 客栈说书:CSS遮罩CSS3 mask/masks详细介绍 « 张鑫旭-鑫空间-鑫生活 (zhangxinxu.com)

只需要一点点改动就行了,把原先的背景用作遮罩背景,如下

.fireworks {
    /*其他样式*/
      background: #FFEFAD;
    -webkit-mask: url('https://imgservices-1252317822.image.myqcloud.com/image/081320210201435/e9951400.png') right top no-repeat;
    -webkit-mask-size: auto 150px;
}
@keyframes fireworks {
    to {
        -webkit-mask-position: 100%;
    }
}

Kapture 2021-08-21 at 12.14.01

再进一步,可以加入颜色的变化动画,比如 黄 → 红 → 紫 → 青,再定义一个关键帧

}
.fireworks {
       /*其他样式*/
    animation: fireworks 2s steps(24) infinite, random 8s steps(1) infinite, random_color 1s infinite;
}
@keyframes random_color {
    0% {
        background-color: #ffefad;
    }
    25% {
        background-color: #ffadad;
    }
    50% {
        background-color: #aeadff;
    }
    75% {
        background-color: #adffd9;
    }
}

可以得到如下的效果

Kapture 2021-08-21 at 12.36.07

是不是变得绚丽多彩了起来?完整代码可以访问 CSS fireworks colors (codepen.io)

七、IE下的降级处理

现代浏览器基本都支持 mask 遮罩了,但是 IE 不支持,所以 IE下就变成了这样

Kapture 2021-08-24 at 22.01.06

因此,IE 下需要降级处理,不用绚丽多彩,只需要随机绽放

那么如何区分 IE 浏览器和现代浏览器呢?其实可以用 IE 不支持的一些选择器就可以了,比如 :default

.fireworks {
    background: url('https://imgservices-1252317822.image.myqcloud.com/image/081320210201435/e9951400.png') right top no-repeat;
    background-size: auto 150px;
}

/*以下现代浏览器支持*/
_:default, .fireworks {
    -webkit-mask: url('https://imgservices-1252317822.image.myqcloud.com/image/081320210201435/e9951400.png') right top no-repeat;
    -webkit-mask-size: auto 150px;
}

八、动画与用户体验

适当的动画可以提升用户体验,但不是所有用户都喜欢动画,尤其是一些装饰类动画,可能觉得花里胡哨的,可能觉得分散了注意力,可能为了省电,甚至部分动画还会对用户造成不良的反应。为此,选择权应该交给用户,用户觉得不需要可以在系统直接关闭动画。

目前大部分的操作系统都可以关闭不必要的动画

  • 在 Windows 10 中:设置 > 轻松获取 > 显示 > 在 Windows 中显示动画。
  • 在 Windows 7 中:控制面板 > 轻松获取 > 使计算机更易于查看 > 关闭不必要动画。
  • 在 MacOS 中:系统偏好 > 辅助使用 > 显示 > 减弱动态效果。
  • 在 iOS 上:设置 > 通用 > 辅助性 > 减弱动态效果。
  • 在 Android 9+ 上:设置 > 辅助性 > 移除动画。

相对应的,CSS 中可以通过媒体查询 prefers-reduced-motion来检测系统是否开启动画减弱功能。

所以,可以再增加这样一段 CSS

@media screen and (prefers-reduced-motion) { 
    /* 禁用不必要的动画 */ 
    .fireworks { 
        animation: none; 
    } 
}

效果如下(这里以macOS为例)

Kapture 2021-08-21 at 15.14.02

可以看到,当勾选 "减弱动态效果" 时,烟花动效就完全消失了。虽然没有什么技术含量,但是却照顾到了一部分人的感受,不知不觉之间就提升了用户体验,何乐不为呢。

九、总结和说明

以上介绍了烟花动画实现的全过程,还包括一些用户体验小技巧,简单总结一下

  1. 选择合适的动画实现方式
  2. CSS 序列帧动画实现的关键是 steps
  3. 可以把多个动画组合起来形成新的动画
  4. 改变图形颜色可以用 mask 实现
  5. IE 和现代浏览器可以用 :default 区分
  6. 有必要跟随系统设置关闭动画,可以借助媒体查询 prefers-reduced-motion

CSS 实现并不复杂,大部分同学应该都能快速上手,但是做的完美其实并不容易。如果觉得还不错,对你有帮助的话,欢迎点赞、收藏、转发❤❤❤


Recommend

About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK