1<!DOCTYPE html>
2<html lang="en">
3<head>
4<meta charset="UTF-8" />
5<meta name="viewport" content="width=device-width,initial-scale=1.0" />
6<title>Minimal Pulsing Ring</title>
7<style>
8 :root{
9 --bg:#222;
10 --size:28px;
11 --stroke:3px;
12 --dur:2.4s;
13 }
14
15 html,body{
16 margin:0;
17 width:100%;
18 height:100%;
19 background:var(--bg);
20 overflow:hidden;
21 }
22
23 body{
24 display:grid;
25 place-items:center;
26 }
27
28 .loader{
29 position:relative;
30 width:var(--size);
31 height:var(--size);
32 }
33
34 .ring,
35 .pulse{
36 position:absolute;
37 inset:0;
38 border-radius:50%;
39 box-sizing:border-box;
40 }
41
42 /* Main visible ring */
43 .ring{
44 border:var(--stroke) solid #0b84c6;
45 animation:
46 ringColor var(--dur) linear infinite,
47 ringScale var(--dur) ease-in-out infinite;
48 filter: drop-shadow(0 0 2px currentColor);
49 }
50
51 /* Soft expanding halo that appears later in the cycle */
52 .pulse{
53 border:2px solid rgba(0,0,0,.0);
54 opacity:0;
55 transform:scale(1);
56 animation:
57 pulseExpand var(--dur) ease-out infinite,
58 pulseColor var(--dur) linear infinite;
59 }
60
61 /* Slight inner dark center to match the hollow look */
62 .loader::after{
63 content:"";
64 position:absolute;
65 inset:7px;
66 border-radius:50%;
67 background:var(--bg);
68 }
69
70 @keyframes ringScale{
71 0%,100% { transform:scale(.72); }
72 22% { transform:scale(1.08); }
73 45% { transform:scale(1.55); }
74 62% { transform:scale(.82); }
75 78% { transform:scale(1.18); }
76 90% { transform:scale(1.02); }
77 }
78
79 @keyframes ringColor{
80 0% { border-color:#0b84c6; }
81 18% { border-color:#1f8b6f; }
82 34% { border-color:#3a3428; opacity:.35; }
83 50% { border-color:#d45a3a; opacity:1; }
84 66% { border-color:#b67a2f; }
85 78% { border-color:#1f8b6f; }
86 88% { border-color:#8a6a3a; }
87 100% { border-color:#d39a43; }
88 }
89
90 @keyframes pulseExpand{
91 0%,58%{
92 transform:scale(1);
93 opacity:0;
94 }
95 68%{
96 opacity:.18;
97 transform:scale(1.35);
98 }
99 82%{
100 opacity:.12;
101 transform:scale(1.7);
102 }
103 100%{
104 opacity:0;
105 transform:scale(2.05);
106 }
107 }
108
109 @keyframes pulseColor{
110 0%,58% { border-color:rgba(0,0,0,0); }
111 68% { border-color:rgba(44,180,150,.45); }
112 82% { border-color:rgba(210,150,70,.35); }
113 92% { border-color:rgba(220,80,70,.35); }
114 100% { border-color:rgba(220,170,80,0); }
115 }
116</style>
117</head>
118<body>
119 <div class="loader" aria-label="loading animation">
120 <div class="pulse"></div>
121 <div class="ring"></div>
122 </div>
123</body>
124</html>