手把手教你实现一团热烈的火焰

0 阅读5分钟

前言

继上次实现一个旋转风车的效果后,这次我就带大家来实现一团热烈的火焰效果,用CSS配合JS方法来实现,十分简单,没有花里胡哨的技巧。话不多说,咱们直接进入主题。

效果预览

最终实现的相关效果如下。

CSS部分

首先我们看到CSS部分,通过样式来实现一团火焰,在CSS中创建了一个动态火焰粒子效果,使用多个半透明的圆形粒子(<span>)通过动画模拟火焰上升消散的视觉效果。

首先是基础布局 (body 样式),相关代码如下。

body {
    margin: 0;
    height: 100vh;
    display: flex;
    align-items: center;
    justify-content: center;
    background: linear-gradient(black, maroon); /* 黑色到深红的渐变背景 */
    overflow: hidden; /* 隐藏超出部分 */
}

让页面居中,背景为黑色到深红的渐变,营造火焰的暗色环境,overflow: hidden 确保火焰粒子不会超出屏幕。

然后是火焰容器 (.flame),相关代码如下。

.flame {
    width: 10em;
    height: 12em;
    font-size: 24px; /* 基准单位 */
    position: relative; /* 为子元素定位提供参照 */
}

火焰区域宽 10em、高 12em(基于 font-size: 24px1em = 24px),允许子粒子绝对定位。

接着是火焰粒子 (.flame span),相关代码如下。

.flame span {
    position: absolute;
    width: 5em;
    height: 5em;
    background: radial-gradient(
        orangered 20%,       /* 中心橙红色 */
        rgba(255, 69, 0, 0) 70% /* 边缘透明 */
    );
    border-radius: 50%; /* 圆形 */
    bottom: 0; /* 从底部开始 */
    left: calc((var(--n) - 1) * 5em / var(--particles)); /* 水平位置 */
    mix-blend-mode: screen; /* 混合模式:提亮 */
    animation: rise 1s ease-in infinite; /* 上升动画 */
    animation-delay: calc(var(--rnd) * 1s); /* 随机延迟 */
    filter: opacity(0); /* 初始透明 */
}

粒子形状是圆形的,径向渐变从橙红(orangered)到透明,模拟火焰发光效果。通过 CSS 变量 --n(粒子序号)和 --particles(总数)计算水平位置,均匀分布,并且让所有粒子从容器底部开始上升。

使用混合模式mix-blend-mode: screen使粒子与背景混合时更亮(类似火焰叠加效果)。

然后定义了一个动画,通过 --rnd(随机值)实现粒子错开上升,filter: opacity(0)表示初始透明,避免突兀出现。

接着是上升动画 (@keyframes rise),相关代码如下。

@keyframes rise {
    from {
        transform: translateY(0) scale(1); /* 起始位置 */
        filter: opacity(0); /* 透明 */
    }
    25% {
        filter: opacity(1); /* 完全显现 */
    }
    to {
        transform: translateY(-10em) scale(0); /* 上升至顶部并缩小 */
        filter: opacity(0); /* 淡出 */
    }
}

起始时,粒子在底部,透明 (opacity(0)),25% 时,完全显现 (opacity(1)),结束 时,上升至顶部 (translateY(-10em)),缩小至消失 (scale(0)),再次透明。最终的动画效果就是粒子从底部升起、放大、再缩小淡出,模拟火焰闪烁上升。

最终效果就是多个橙红色圆形粒子从底部上升,过程中闪烁并消散,粒子位置和动画时间错开,形成自然火焰的随机感。通过简洁的 CSS 实现了复杂的粒子动画效果。

JS部分

粒子样式由 CSS 的 .flame span 控制(大小、颜色、动画等),接下来的JavaScript 则负责动态生成和定位。相关代码如下。

<script>
      const COUNT_OF_PARTICLES = 100
const container = document.querySelector('.flame')

container.style.setProperty('--particles', COUNT_OF_PARTICLES)

Array(COUNT_OF_PARTICLES).fill('').forEach((particle, i) => {
    let span = document.createElement('span')
    span.style.setProperty('--n', i + 1)
    span.style.setProperty('--rnd', Math.random())
    container.appendChild(span)
})
    </script>

这里动态创建了 100 个火焰粒子<span> 元素),并将它们添加到 .flame 容器中,同时为每个粒子设置 CSS 变量以控制其位置和动画延迟。

首先通过 document.querySelector 获取 HTML 中类名为 flame 的元素(火焰的容器)。在 .flame 容器上设置 CSS 变量 --particles,值为 100。在 CSS 中通过 var(--particles) 计算粒子的水平位置(见上面 CSS 中的 left 属性)。

接着动态生成粒子, 创建空数组Array(COUNT_OF_PARTICLES).fill('') 生成一个长度为 100 的数组,遍历数组,对每个元素执行回调函数,参数 i 为当前索引(从 0 开始),创建粒子:每次循环创建一个 <span> 元素。

设置 CSS 变量: - --n:粒子序号(i + 1,范围 1100),用于计算水平位置。 - --rnd:随机数(Math.random(),范围 01),用于动画延迟。

最终添加到容器:将粒子 span 插入到 .flame 中。

在 CSS 中通过 calc((var(--n) - 1) * 5em / var(--particles)) 计算每个粒子的 left 位置,实现水平均匀分布。例如:第一个粒子(--n: 1)的 left0,最后一个(--n: 100)的 left4.95em。通过 calc(var(--rnd) * 1s) 设置 animation-delay,使粒子随机错开上升,避免同步移动。

这样处理完成后,最终效果就是100 个粒子从容器底部升起,水平均匀分布,每个粒子的上升动画有随机延迟,形成自然闪烁效果。

总结

以上就是整个效果的实现过程了,纯 CSS 实现,代码简单易懂。另外,感兴趣的小伙伴们还可以在现有基础上发散思维,比如增加点其他效果,或者更改颜色等等。关于该效果如果大家有更好的想法欢迎在评论区分享,互相学习。最后,完整代码在码上掘金里可以查看,如果有什么问题大家在评论区里讨论~