CSS制作爆炸效果的粒子动画

3
我想模拟一个粒子爆炸,从屏幕中心到边缘(使用CSS,我保证不会将其用于恶意目的)。
这是一个示意图,以便您了解我的意思:
之前:

BEFORE

之后:

AFTER

我尝试使用以下的HTML/CSS/JS,但它没有起作用(点仍然停留在屏幕中央):
HTML代码只有这个:
<div id="animated"></div>

CSS:

// SCSS
#animated {
  position: relative; 
  width: 100%;
  height: 100%;
  overflow: hidden;

  .particle {
    position: absolute;
    left: 50%;
    top: 50%;
    width: 10px;
    height: 10px;
    transition: transform 1s ease-in-out;

    &.on {
      transform: translate(-30vw, -30vh);
    }

    &::after {
      position: absolute;
      content: "";
      width: 10px;
      height: 10px;
      border-radius: 50%;
      background: red;
    }
  }
}

而且JavaScript:

document.addEventListener('DOMContentLoaded', onLoad);

function onLoad() {
  // animate
  for(var i = 0; i < 360; i+=5) {
    const particle = createParticle(animated, i);
  }
}

function createParticle(parentElem, rotation) {
  const particle = document.createElement('div');
  particle.style.transform = `rotate(${rotation}deg)`;
  particle.classList.add('particle');
  particle.classList.add('on'); // turn on
  parentElem.appendChild(particle);

  return particle;
}

这是一个 CodePen 的链接:https://codepen.io/floatingrock/pen/KKpxpvJ
1个回答

4

这是一个基于CSS变量的想法,只需要少量代码就可以轻松调整。

为了获得更好的效果,请在全屏模式下运行:

document.addEventListener('DOMContentLoaded', onLoad);

function onLoad() {
  let parentElem = document.querySelector('.container');
  for (var i = 0; i < 360; i += 10) {
    const particle = document.createElement('div');
    particle.style = `--r:${i}deg`;
    parentElem.appendChild(particle);
  }
}
.container {
  width: 20px;
  height: 20px;
  position: fixed;
  top: 50%;
  left: 50%;
  transform: translate(-50%, -50%);
}

.container>div {
  position: absolute;
  top: 0;
  left: 0;
  width: 100%;
  height: 100%;
  border-radius: 50%;
  background: red;
  transform: rotate(var(--r, 0deg)) translate(0);
  animation: splash 1s infinite alternate 1s;
}

@keyframes splash {
  to {
    transform: rotate(var(--r, 0deg)) translate(44vmin);
  }
}
<div class="container">
</div>

您可以针对其他类型的动画考虑不同的延迟:

document.addEventListener('DOMContentLoaded', onLoad);

function onLoad() {
  let parentElem = document.querySelector('.container');
  for (var i = 0; i < 360; i += 10) {
    const particle = document.createElement('div');
    particle.style = `--r:${i}deg;--d:${(i/360)}s`;
    parentElem.appendChild(particle);
  }
}
.container {
  width: 20px;
  height: 20px;
  position: fixed;
  top: 50%;
  left: 50%;
  transform: translate(-50%, -50%);
}

.container>div {
  position: absolute;
  top: 0;
  left: 0;
  width: 100%;
  height: 100%;
  border-radius: 50%;
  background: red;
  transform: rotate(var(--r, 0deg)) translate(0);
  animation: splash 1s infinite alternate var(--d,0s);
}

@keyframes splash {
  to {
    transform: rotate(var(--r, 0deg)) translate(44vmin);
  }
}
<div class="container">
</div>

我们仍然可以通过更少的CSS来优化代码:

document.addEventListener('DOMContentLoaded', onLoad);

function onLoad() {
  let parentElem = document.querySelector('.container');
  for (var i = 0; i < 360; i += 10) {
    const particle = document.createElement('div');
    particle.style = `--r:${i}deg`;
    parentElem.appendChild(particle);
  }
}
.container > div {
  position: fixed;
  top: 50%;
  left: 50%;
  width: 20px;
  height: 20px;
  border-radius: 50%;
  background: red;
  transform:translate(-50%, -50%) rotate(var(--r, 0deg)) translate(0);
  animation: splash 1s infinite alternate 1s;
}

@keyframes splash {
  to {
    transform:translate(-50%, -50%) rotate(var(--r, 0deg)) translate(calc(50vmin - 10px));
  }
}


/* Irrelevant styles */
html {
  height:100%;
  border:1px solid blue; /* screen border*/
  box-sizing:border-box;
  background:linear-gradient(green,green) center/10px 10px no-repeat; /* the center of the screen */
}
body {
 margin:0;
}
<div class="container">
</div>

转换的顺序很重要。相关内容可参考:为什么转换的顺序很重要?rotate/scale与scale/rotate的结果不同

这太棒了 - 克服了需要伪元素和“on”类的需求。 - FloatingRock
@FloatingRock添加了另一个优化的版本。 - Temani Afif
为什么在这里使用了两次 translatetransform:translate(-50%, -50%) rotate(var(--r, 0deg)) translate(0); - FloatingRock
@FloatingRock 第一个将居中,第二个(旋转)将旋转元素,最后一个将移动元素并创建平移动画。顺序很重要,因为每个变换都受前一个变换的影响。 - Temani Afif
啊,所以没有最后的 translate(0) 就不会触发动画?我之前不知道这个。 - FloatingRock
@FloatingRock 在这种情况下,你可以省略 translate(0),因为它是一个空变换,浏览器会默认添加它。我保留它是为了清晰起见,以便我们理解我们正在从 0 到 50vmin 进行动画。 - Temani Afif

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接