15 Pure CSS Loading Animations
Heat-Map Compass
A premium navigation loader for property and travel platforms — a brass compass dial with cardinal points lighting one at a time as warm "heat" rings pulse outward. A monospace coordinate readout drifts below, suggesting the system is "scanning your neighbourhood". Honest narrative for indeterminate location-aware loads.
Heat-Map Compass the 4th of 15 designs in the 15 Pure CSS Loading Animations collection. The design pairs CSS styling with a small amount of JavaScript for interactivity. Copy the HTML, CSS and JavaScript panels below into your project — the JS is self-contained, has zero dependencies, and is safe to drop into any framework (React, Vue, Svelte, plain HTML). The design honours prefers-reduced-motion and uses real semantic markup, so it ships accessibility-ready out of the box.
Live preview
The code
<figure class="hc-loader" role="status" aria-label="Searching nearby properties">
<span class="hc-rings" aria-hidden="true">
<span class="hc-ring"></span>
<span class="hc-ring"></span>
<span class="hc-ring"></span>
</span>
<span class="hc-dial" aria-hidden="true">
<span class="hc-mark hc-mark-n">N</span>
<span class="hc-mark hc-mark-e">E</span>
<span class="hc-mark hc-mark-s">S</span>
<span class="hc-mark hc-mark-w">W</span>
<span class="hc-needle"></span>
<span class="hc-pivot"></span>
</span>
<figcaption class="hc-coord" aria-live="polite" data-hc-coord>51.5074°N · 0.1278°W</figcaption>
</figure> .hc-loader {
position: relative;
width: 180px;
height: 180px;
margin: 0;
padding: 0;
display: grid;
place-items: center;
font-family: system-ui, sans-serif;
}
.hc-rings {
position: absolute;
inset: 0;
display: grid;
place-items: center;
pointer-events: none;
}
.hc-ring {
position: absolute;
width: 84px;
height: 84px;
border-radius: 50%;
border: 1.5px solid #5b8cb8;
opacity: 0;
animation: hcRing 2.6s ease-out infinite;
}
.hc-ring:nth-child(1) {
animation-delay: 0s;
}
.hc-ring:nth-child(2) {
animation-delay: 0.85s;
}
.hc-ring:nth-child(3) {
animation-delay: 1.7s;
}
.hc-dial {
position: relative;
width: 96px;
height: 96px;
border-radius: 50%;
background:
radial-gradient(circle at 30% 25%, rgba(255, 212, 121, 0.12) 0%, transparent 55%),
radial-gradient(circle at 50% 50%, #1a1d2e 0%, #0f1220 70%);
border: 2px solid #d4af37;
box-shadow:
inset 0 0 18px rgba(212, 175, 55, 0.18),
0 4px 18px -4px rgba(212, 175, 55, 0.4),
0 0 0 1px rgba(212, 175, 55, 0.25);
animation: hcDialSpin 18s linear infinite;
}
.hc-mark {
position: absolute;
font-family: "JetBrains Mono", monospace;
font-size: 10px;
font-weight: 700;
color: rgba(212, 175, 55, 0.4);
letter-spacing: 0.06em;
transition: color 0.3s ease;
animation: hcMark 2.6s ease-in-out infinite;
}
.hc-mark-n {
top: 4px;
left: 50%;
transform: translateX(-50%);
animation-delay: 0s;
}
.hc-mark-e {
right: 6px;
top: 50%;
transform: translateY(-50%);
animation-delay: 0.65s;
}
.hc-mark-s {
bottom: 4px;
left: 50%;
transform: translateX(-50%);
animation-delay: 1.3s;
}
.hc-mark-w {
left: 6px;
top: 50%;
transform: translateY(-50%);
animation-delay: 1.95s;
}
.hc-needle {
position: absolute;
top: 50%;
left: 50%;
width: 2px;
height: 70px;
margin: -35px 0 0 -1px;
background: linear-gradient(180deg, #ffd479 0%, #d4af37 48%, #2a3045 52%, #1a1d2e 100%);
border-radius: 2px;
transform-origin: center center;
animation: hcNeedle 5s cubic-bezier(0.5, 0.05, 0.3, 0.95) infinite;
box-shadow: 0 0 8px rgba(212, 175, 55, 0.4);
}
.hc-pivot {
position: absolute;
top: 50%;
left: 50%;
width: 6px;
height: 6px;
margin: -3px 0 0 -3px;
background: #ffd479;
border-radius: 50%;
box-shadow:
0 0 0 2px #1a1d2e,
0 0 10px rgba(255, 212, 121, 0.6);
}
.hc-coord {
position: absolute;
bottom: -22px;
left: 50%;
transform: translateX(-50%);
font-family: "JetBrains Mono", monospace;
font-size: 10.5px;
font-weight: 600;
color: #5eead4;
letter-spacing: 0.04em;
white-space: nowrap;
font-variant-numeric: tabular-nums;
}
@media (prefers-reduced-motion: reduce) {
.hc-ring,
.hc-dial,
.hc-mark,
.hc-needle {
animation: none;
}
.hc-mark {
color: #ffd479;
}
}
@keyframes hcRing {
0% {
transform: scale(0.6);
border-color: #5b8cb8;
opacity: 0;
}
15% {
opacity: 0.9;
}
60% {
border-color: #d4af37;
}
100% {
transform: scale(2.05);
border-color: #d4af37;
opacity: 0;
}
}
@keyframes hcDialSpin {
to {
transform: rotate(360deg);
}
}
@keyframes hcMark {
0%,
80%,
100% {
color: rgba(212, 175, 55, 0.4);
text-shadow: none;
}
10%,
30% {
color: #ffd479;
text-shadow: 0 0 8px rgba(255, 212, 121, 0.7);
}
}
@keyframes hcNeedle {
0% {
transform: rotate(-22deg);
}
25% {
transform: rotate(80deg);
}
50% {
transform: rotate(-40deg);
}
75% {
transform: rotate(140deg);
}
100% {
transform: rotate(-22deg);
}
} // Cycles the coordinate readout to suggest a real "scanning" load.
var hcCoords = [
"51.5074°N · 0.1278°W", // London
"40.7128°N · 74.0060°W", // New York
"34.0522°N · 118.2437°W", // Los Angeles
"48.8566°N · 2.3522°E", // Paris
"35.6762°N · 139.6503°E", // Tokyo
];
document.querySelectorAll("[data-hc-coord]").forEach(function (node) {
var i = 0;
setInterval(function () {
i = (i + 1) % hcCoords.length;
node.textContent = hcCoords[i];
}, 1900);
});