AI CSS Animations

Floating Hearts Background

Hearts in three shades rise from the bottom of a blush backdrop, swaying, beating and fading out near the top. Each heart is four gradients on one pseudo-element, no clip-path or SVG.

Also known as: floating hearts css, valentine background css, hearts animation background.

HTML

<div class="bgx-floating-hearts" aria-hidden="true"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></div>

CSS

.bgx-floating-hearts {
  --c: var(--bgx-color, #3b82f6);
  font-size: var(--bgx-size, 16px);
  position: absolute;
  inset: 0;
  overflow: hidden;
  --heart: color-mix(in oklab, var(--c) 25%, #ff4f8b);
  background: linear-gradient(to top, color-mix(in srgb, var(--heart) 20%, #fff), color-mix(in srgb, var(--c) 4%, #fff));}
.bgx-floating-hearts span {
  position: absolute;
  top: 0;
  left: var(--x);
  height: 100%;
  animation: bgx-floating-hearts-rise var(--dur) linear var(--delay) infinite;
}
.bgx-floating-hearts span::before {
  content: "";
  position: absolute;
  bottom: 0;
  left: 0;
  width: var(--s);
  height: var(--s);
  background:
    radial-gradient(circle at 60% 65%, var(--k) 64%, transparent 65%) top left / 51% 51%,
    radial-gradient(circle at 40% 65%, var(--k) 64%, transparent 65%) top right / 51% 51%,
    linear-gradient(to bottom left, var(--k) 43%, transparent 43%) bottom left / 51% 51%,
    linear-gradient(to bottom right, var(--k) 43%, transparent 43%) bottom right / 51% 51%;
  background-repeat: no-repeat;
  opacity: 0;
  animation:
    bgx-floating-hearts-sway var(--sway) ease-in-out var(--delay) infinite alternate,
    bgx-floating-hearts-beat 1.6s ease-in-out var(--delay) infinite,
    bgx-floating-hearts-fade var(--dur) linear var(--delay) infinite;
}
.bgx-floating-hearts span:nth-child(3n + 1) { --k: var(--heart); }
.bgx-floating-hearts span:nth-child(3n + 2) { --k: color-mix(in srgb, var(--heart) 55%, #fff); }
.bgx-floating-hearts span:nth-child(3n) { --k: color-mix(in oklab, var(--heart), var(--c) 45%); }
.bgx-floating-hearts span:nth-child(1) { --x: 40.8%; --s: 1.86em; --dur: 6.34s; --delay: -9.06s; --sway: 1.74s; }
.bgx-floating-hearts span:nth-child(2) { --x: 70.3%; --s: 0.94em; --dur: 8.45s; --delay: -1.48s; --sway: 1.97s; }
.bgx-floating-hearts span:nth-child(3) { --x: 10.7%; --s: 1.91em; --dur: 6.85s; --delay: -7.36s; --sway: 1.63s; }
.bgx-floating-hearts span:nth-child(4) { --x: 91.5%; --s: 1.47em; --dur: 6.5s; --delay: -8.63s; --sway: 2.17s; }
.bgx-floating-hearts span:nth-child(5) { --x: 86.4%; --s: 1.33em; --dur: 9.95s; --delay: -5.71s; --sway: 1.61s; }
.bgx-floating-hearts span:nth-child(6) { --x: 36.3%; --s: 1.13em; --dur: 9.36s; --delay: -1.59s; --sway: 2.27s; }
.bgx-floating-hearts span:nth-child(7) { --x: 16.5%; --s: 1.01em; --dur: 9.02s; --delay: -9.04s; --sway: 1.92s; }
.bgx-floating-hearts span:nth-child(8) { --x: 97.8%; --s: 1.36em; --dur: 7.75s; --delay: -5s; --sway: 2.03s; }
.bgx-floating-hearts span:nth-child(9) { --x: 51.5%; --s: 1.82em; --dur: 7.06s; --delay: -3.95s; --sway: 2.1s; }
.bgx-floating-hearts span:nth-child(10) { --x: 45.4%; --s: 1.67em; --dur: 9.66s; --delay: -4.58s; --sway: 2.06s; }
.bgx-floating-hearts span:nth-child(11) { --x: 79.7%; --s: 0.95em; --dur: 8.35s; --delay: -8.44s; --sway: 2.78s; }
.bgx-floating-hearts span:nth-child(12) { --x: 29%; --s: 0.92em; --dur: 6.36s; --delay: -6.45s; --sway: 2.27s; }
.bgx-floating-hearts span:nth-child(13) { --x: 23.5%; --s: 0.81em; --dur: 8.29s; --delay: -3.7s; --sway: 2.47s; }
.bgx-floating-hearts span:nth-child(14) { --x: 64.9%; --s: 1.97em; --dur: 7.2s; --delay: -5.71s; --sway: 1.95s; }
.bgx-floating-hearts span:nth-child(15) { --x: 59.8%; --s: 1.42em; --dur: 8.35s; --delay: -8.53s; --sway: 2.56s; }
.bgx-floating-hearts span:nth-child(16) { --x: 1.8%; --s: 0.82em; --dur: 6.5s; --delay: -0.97s; --sway: 1.83s; }
@keyframes bgx-floating-hearts-rise {
  from { transform: translateY(var(--s)); }
  to   { transform: translateY(-100%); }
}
@keyframes bgx-floating-hearts-sway {
  from { translate: -0.8em 0; rotate: -12deg; }
  to   { translate: 0.8em 0; rotate: 12deg; }
}
@keyframes bgx-floating-hearts-beat {
  0%, 30%, 100% { transform: scale(1); }
  12%           { transform: scale(1.16); }
  22%           { transform: scale(1.06); }
}
@keyframes bgx-floating-hearts-fade {
  0%   { opacity: 0; }
  10%  { opacity: 0.9; }
  65%  { opacity: 0.9; }
  90%  { opacity: 0; }
  100% { opacity: 0; }
}

@media (prefers-reduced-motion: reduce) {
  .bgx-floating-hearts, .bgx-floating-hearts *, .bgx-floating-hearts::before, .bgx-floating-hearts::after, .bgx-floating-hearts *::before, .bgx-floating-hearts *::after {
    animation-duration: 0.01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.01ms !important;
  }
}

Customizing this snippet

  • Color: set --bgx-color on the element or a parent. Currently previewing #3b82f6.
  • Pattern scale: set --bgx-size. Every other dimension is in em, so the whole thing scales together. Currently previewing 16px.
  • Speed: change the duration on the transition or animation shorthand. Staggered delays are relative, so they keep their rhythm.
  • Reduced motion: the rule at the end of the CSS turns the motion off for people who asked their OS for less of it. Keep it.

Similar animated backgrounds