A glowing accretion disk swirls around a black hole, passing behind it and in front of it, ringed by a thin halo of bent light. The front half of the disk is a second copy clipped with inset().
Also known as: black hole animation css, accretion disk css, interstellar black hole css.
<div class="bgx-black-hole" aria-hidden="true"><div class="bgx-black-hole-disk"><span></span></div><i></i><div class="bgx-black-hole-disk"><span></span></div></div>
.bgx-black-hole {
--c: var(--bgx-color, #3b82f6);
font-size: var(--bgx-size, 16px);
position: absolute;
inset: 0;
overflow: hidden;
background: radial-gradient(circle at 50% 50%, color-mix(in srgb, var(--c) 24%, #0a0c1c), #020207 62%);}
.bgx-black-hole::before {
content: "";
position: absolute;
inset: 0;
background-size: 11em 11em;
background-image:
radial-gradient(circle 0.07em at 4.2% 53.6%, rgb(255 255 255 / 0.5) 50%, transparent),
radial-gradient(circle 0.07em at 13.7% 78.8%, rgb(255 255 255 / 0.5) 50%, transparent),
radial-gradient(circle 0.07em at 35.8% 47.7%, rgb(255 255 255 / 0.5) 50%, transparent),
radial-gradient(circle 0.07em at 56.6% 68.8%, rgb(255 255 255 / 0.5) 50%, transparent),
radial-gradient(circle 0.07em at 81.9% 39.3%, rgb(255 255 255 / 0.5) 50%, transparent),
radial-gradient(circle 0.07em at 90.4% 89.3%, rgb(255 255 255 / 0.5) 50%, transparent),
radial-gradient(circle 0.07em at 8.6% 44.8%, rgb(255 255 255 / 0.5) 50%, transparent),
radial-gradient(circle 0.07em at 68% 34.4%, rgb(255 255 255 / 0.5) 50%, transparent),
radial-gradient(circle 0.07em at 17.8% 54.4%, rgb(255 255 255 / 0.5) 50%, transparent),
radial-gradient(circle 0.07em at 87.8% 15.5%, rgb(255 255 255 / 0.5) 50%, transparent);
}
.bgx-black-hole-disk {
position: absolute;
top: 50%;
left: 50%;
width: 26em;
height: 26em;
margin: -13em;
transform: rotate(-9deg) scaleY(0.2);
}
.bgx-black-hole-disk:last-child {
clip-path: inset(50% 0 0);
}
.bgx-black-hole-disk span {
position: absolute;
inset: 0;
border-radius: 50%;
background: conic-gradient(color-mix(in srgb, var(--c) 45%, #fff), color-mix(in srgb, var(--c) 70%, transparent) 25%, #fff 42%, color-mix(in srgb, var(--c) 60%, transparent) 62%, color-mix(in srgb, var(--c) 35%, #fff) 82%, color-mix(in srgb, var(--c) 45%, #fff));
mask: radial-gradient(closest-side, transparent 30%, #000 36%, rgb(0 0 0 / 0.55) 60%, transparent);
animation: bgx-black-hole-spin 6s linear infinite;
}
.bgx-black-hole i {
position: absolute;
top: 50%;
left: 50%;
width: 6em;
height: 6em;
margin: -3em;
border-radius: 50%;
background: #000;
box-shadow:
0 0 0 0.1em color-mix(in srgb, var(--c) 35%, #fff),
0 0 1.2em 0.35em color-mix(in srgb, var(--c) 60%, transparent),
0 0 4em 1.4em color-mix(in srgb, var(--c) 22%, transparent);
}
.bgx-black-hole i::before {
content: "";
position: absolute;
inset: -1.1em;
border-radius: 50%;
background: radial-gradient(closest-side, transparent 72%, color-mix(in srgb, var(--c) 45%, #fff) 80%, color-mix(in srgb, var(--c) 40%, transparent) 88%, transparent);
animation: bgx-black-hole-halo 3s ease-in-out infinite alternate;
}
@keyframes bgx-black-hole-spin {
to { transform: rotate(360deg); }
}
@keyframes bgx-black-hole-halo {
from { opacity: 0.55; transform: scale(0.98); }
to { opacity: 1; transform: scale(1.03); }
}
@media (prefers-reduced-motion: reduce) {
.bgx-black-hole, .bgx-black-hole *, .bgx-black-hole::before, .bgx-black-hole::after, .bgx-black-hole *::before, .bgx-black-hole *::after {
animation-duration: 0.01ms !important;
animation-iteration-count: 1 !important;
transition-duration: 0.01ms !important;
}
}The same effect using Tailwind utility classes. No custom CSS or config needed.
<div class="absolute inset-0 overflow-hidden bg-[radial-gradient(circle_at_50%_50%,#131a3f,#020207_62%)] text-[16px]" aria-hidden="true">
<div class="absolute left-1/2 top-1/2 -ml-[13em] -mt-[13em] h-[26em] w-[26em] [transform:rotate(-9deg)_scaleY(0.2)]">
<div class="absolute inset-0 animate-[spin_6s_linear_infinite] rounded-full bg-[conic-gradient(#9ec5fb,rgba(59,130,246,0.7)_25%,#fff_42%,rgba(59,130,246,0.6)_62%,#c3dafc_82%,#9ec5fb)] [mask:radial-gradient(closest-side,transparent_30%,#000_36%,rgba(0,0,0,0.55)_60%,transparent)]"></div>
</div>
<div class="absolute left-1/2 top-1/2 -ml-[3em] -mt-[3em] h-[6em] w-[6em] rounded-full bg-black shadow-[0_0_0_0.1em_#c3dafc,0_0_1.2em_0.35em_rgba(59,130,246,0.6),0_0_4em_1.4em_rgba(59,130,246,0.22)]">
<div class="absolute -inset-[1.1em] animate-pulse rounded-full bg-[radial-gradient(closest-side,transparent_72%,#b3cffb_80%,rgba(59,130,246,0.4)_88%,transparent)]"></div>
</div>
<div class="absolute left-1/2 top-1/2 -ml-[13em] -mt-[13em] h-[26em] w-[26em] [clip-path:inset(50%_0_0)] [transform:rotate(-9deg)_scaleY(0.2)]">
<div class="absolute inset-0 animate-[spin_6s_linear_infinite] rounded-full bg-[conic-gradient(#9ec5fb,rgba(59,130,246,0.7)_25%,#fff_42%,rgba(59,130,246,0.6)_62%,#c3dafc_82%,#9ec5fb)] [mask:radial-gradient(closest-side,transparent_30%,#000_36%,rgba(0,0,0,0.55)_60%,transparent)]"></div>
</div>
</div>--bgx-color on the element or a parent.
Currently previewing #3b82f6.--bgx-size. Every other dimension is in
em, so the whole thing scales together. Currently previewing 16px.transition or animation
shorthand. Staggered delays are relative, so they keep their rhythm.