16 CSS Frosted Glass Effects13 / 16
Glass Music Player UI
A floating glass music player that blurs a rich purple-coral "album art" gradient behind it. Features a rotating vinyl disc that spins when playing, animated progress bar, track cycling with skip buttons, like toggle, and shuffle/repeat controls.
Published
The code
<div class="fg-13">
<div class="fg-08__art-bg" aria-hidden="true">
<div class="fg-08__orb fg-08__orb--1"></div>
<div class="fg-08__orb fg-08__orb--2"></div>
<div class="fg-08__orb fg-08__orb--3"></div>
</div>
<div class="fg-08__player" role="region" aria-label="Music player">
<div class="fg-08__disc-wrap" aria-hidden="true">
<div class="fg-08__disc" id="fg-13-disc">
<div class="fg-08__disc-ring fg-08__disc-ring--1"></div>
<div class="fg-08__disc-ring fg-08__disc-ring--2"></div>
<div class="fg-08__disc-center"></div>
<div class="fg-08__disc-dot"></div>
</div>
</div>
<div class="fg-08__info">
<div class="fg-08__track-row">
<div>
<p class="fg-08__track" id="fg-13-track">Neon Horizons</p>
<p class="fg-08__artist" id="fg-13-artist">Echo Pulse</p>
</div>
<button class="fg-08__like" id="fg-13-like" aria-label="Like track">
<svg class="fg-08__like-e" width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M20.84 4.61a5.5 5.5 0 0 0-7.78 0L12 5.67l-1.06-1.06a5.5 5.5 0 0 0-7.78 7.78l1.06 1.06L12 21.23l7.78-7.78 1.06-1.06a5.5 5.5 0 0 0 0-7.78z"/></svg>
<svg class="fg-08__like-f" width="18" height="18" viewBox="0 0 24 24" fill="#f87171" stroke="#f87171" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M20.84 4.61a5.5 5.5 0 0 0-7.78 0L12 5.67l-1.06-1.06a5.5 5.5 0 0 0-7.78 7.78l1.06 1.06L12 21.23l7.78-7.78 1.06-1.06a5.5 5.5 0 0 0 0-7.78z"/></svg>
</button>
</div>
<div class="fg-08__prog-wrap">
<div class="fg-08__prog-bar" aria-label="Playback progress"><div class="fg-08__prog-fill" id="fg-13-prog"></div></div>
<div class="fg-08__times"><span id="fg-13-cur">0:00</span><span id="fg-13-dur">3:47</span></div>
</div>
<div class="fg-08__controls">
<button class="fg-08__ctrl fg-08__ctrl--sm" id="fg-13-shuf" aria-label="Shuffle" aria-pressed="false">
<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><polyline points="16 3 21 3 21 8"/><line x1="4" y1="20" x2="21" y2="3"/><polyline points="21 16 21 21 16 21"/><line x1="15" y1="15" x2="21" y2="21"/></svg>
</button>
<button class="fg-08__ctrl" id="fg-13-prev" aria-label="Previous track">
<svg width="20" height="20" viewBox="0 0 24 24" fill="currentColor"><polygon points="19 20 9 12 19 4 19 20"/><line x1="5" y1="19" x2="5" y2="5" stroke="currentColor" stroke-width="2" stroke-linecap="round"/></svg>
</button>
<button class="fg-08__ctrl fg-08__ctrl--play" id="fg-13-play" aria-label="Play" aria-pressed="false">
<svg class="fg-08__play-icon" width="22" height="22" viewBox="0 0 24 24" fill="currentColor"><polygon points="5 3 19 12 5 21 5 3"/></svg>
<svg class="fg-08__pause-icon" width="22" height="22" viewBox="0 0 24 24" fill="currentColor" style="display:none"><rect x="6" y="4" width="4" height="16" rx="1"/><rect x="14" y="4" width="4" height="16" rx="1"/></svg>
</button>
<button class="fg-08__ctrl" id="fg-13-next" aria-label="Next track">
<svg width="20" height="20" viewBox="0 0 24 24" fill="currentColor"><polygon points="5 4 15 12 5 20 5 4"/><line x1="19" y1="5" x2="19" y2="19" stroke="currentColor" stroke-width="2" stroke-linecap="round"/></svg>
</button>
<button class="fg-08__ctrl fg-08__ctrl--sm" id="fg-13-rep" aria-label="Repeat" aria-pressed="false">
<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><polyline points="17 1 21 5 17 9"/><path d="M3 11V9a4 4 0 0 1 4-4h14"/><polyline points="7 23 3 19 7 15"/><path d="M21 13v2a4 4 0 0 1-4 4H3"/></svg>
</button>
</div>
<div class="fg-08__vol-wrap" aria-label="Volume">
<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><polygon points="11 5 6 9 2 9 2 15 6 15 11 19 11 5"/><path d="M15.54 8.46a5 5 0 0 1 0 7.07"/><path d="M19.07 4.93a10 10 0 0 1 0 14.14"/></svg>
<div class="fg-08__vol-bar"><div class="fg-08__vol-fill"></div></div>
</div>
</div>
</div>
</div><div class="fg-13">
<div class="fg-08__art-bg" aria-hidden="true">
<div class="fg-08__orb fg-08__orb--1"></div>
<div class="fg-08__orb fg-08__orb--2"></div>
<div class="fg-08__orb fg-08__orb--3"></div>
</div>
<div class="fg-08__player" role="region" aria-label="Music player">
<div class="fg-08__disc-wrap" aria-hidden="true">
<div class="fg-08__disc" id="fg-13-disc">
<div class="fg-08__disc-ring fg-08__disc-ring--1"></div>
<div class="fg-08__disc-ring fg-08__disc-ring--2"></div>
<div class="fg-08__disc-center"></div>
<div class="fg-08__disc-dot"></div>
</div>
</div>
<div class="fg-08__info">
<div class="fg-08__track-row">
<div>
<p class="fg-08__track" id="fg-13-track">Neon Horizons</p>
<p class="fg-08__artist" id="fg-13-artist">Echo Pulse</p>
</div>
<button class="fg-08__like" id="fg-13-like" aria-label="Like track">
<svg class="fg-08__like-e" width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M20.84 4.61a5.5 5.5 0 0 0-7.78 0L12 5.67l-1.06-1.06a5.5 5.5 0 0 0-7.78 7.78l1.06 1.06L12 21.23l7.78-7.78 1.06-1.06a5.5 5.5 0 0 0 0-7.78z"/></svg>
<svg class="fg-08__like-f" width="18" height="18" viewBox="0 0 24 24" fill="#f87171" stroke="#f87171" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M20.84 4.61a5.5 5.5 0 0 0-7.78 0L12 5.67l-1.06-1.06a5.5 5.5 0 0 0-7.78 7.78l1.06 1.06L12 21.23l7.78-7.78 1.06-1.06a5.5 5.5 0 0 0 0-7.78z"/></svg>
</button>
</div>
<div class="fg-08__prog-wrap">
<div class="fg-08__prog-bar" aria-label="Playback progress"><div class="fg-08__prog-fill" id="fg-13-prog"></div></div>
<div class="fg-08__times"><span id="fg-13-cur">0:00</span><span id="fg-13-dur">3:47</span></div>
</div>
<div class="fg-08__controls">
<button class="fg-08__ctrl fg-08__ctrl--sm" id="fg-13-shuf" aria-label="Shuffle" aria-pressed="false">
<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><polyline points="16 3 21 3 21 8"/><line x1="4" y1="20" x2="21" y2="3"/><polyline points="21 16 21 21 16 21"/><line x1="15" y1="15" x2="21" y2="21"/></svg>
</button>
<button class="fg-08__ctrl" id="fg-13-prev" aria-label="Previous track">
<svg width="20" height="20" viewBox="0 0 24 24" fill="currentColor"><polygon points="19 20 9 12 19 4 19 20"/><line x1="5" y1="19" x2="5" y2="5" stroke="currentColor" stroke-width="2" stroke-linecap="round"/></svg>
</button>
<button class="fg-08__ctrl fg-08__ctrl--play" id="fg-13-play" aria-label="Play" aria-pressed="false">
<svg class="fg-08__play-icon" width="22" height="22" viewBox="0 0 24 24" fill="currentColor"><polygon points="5 3 19 12 5 21 5 3"/></svg>
<svg class="fg-08__pause-icon" width="22" height="22" viewBox="0 0 24 24" fill="currentColor" style="display:none"><rect x="6" y="4" width="4" height="16" rx="1"/><rect x="14" y="4" width="4" height="16" rx="1"/></svg>
</button>
<button class="fg-08__ctrl" id="fg-13-next" aria-label="Next track">
<svg width="20" height="20" viewBox="0 0 24 24" fill="currentColor"><polygon points="5 4 15 12 5 20 5 4"/><line x1="19" y1="5" x2="19" y2="19" stroke="currentColor" stroke-width="2" stroke-linecap="round"/></svg>
</button>
<button class="fg-08__ctrl fg-08__ctrl--sm" id="fg-13-rep" aria-label="Repeat" aria-pressed="false">
<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><polyline points="17 1 21 5 17 9"/><path d="M3 11V9a4 4 0 0 1 4-4h14"/><polyline points="7 23 3 19 7 15"/><path d="M21 13v2a4 4 0 0 1-4 4H3"/></svg>
</button>
</div>
<div class="fg-08__vol-wrap" aria-label="Volume">
<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><polygon points="11 5 6 9 2 9 2 15 6 15 11 19 11 5"/><path d="M15.54 8.46a5 5 0 0 1 0 7.07"/><path d="M19.07 4.93a10 10 0 0 1 0 14.14"/></svg>
<div class="fg-08__vol-bar"><div class="fg-08__vol-fill"></div></div>
</div>
</div>
</div>
</div>.fg-13,
.fg-13 *,
.fg-13 *::before,
.fg-13 *::after {
box-sizing: border-box;
margin: 0;
padding: 0;
}
.fg-13 ::selection {
background: rgba(167,139,250,.5);
color: #fff;
}
.fg-13 {
--c-bg: #0d0514;
--c-a: #a855f7;
--c-a2: #ec4899;
--c-glass: rgba(255,255,255,.07);
--c-border: rgba(255,255,255,.12);
--c-text: #f0eeff;
--c-muted: rgba(240,238,255,.5);
--t: .25s ease;
font-family: system-ui,-apple-system,'Segoe UI',sans-serif;
min-height: 100vh;
display: flex;
align-items: center;
justify-content: center;
background: var(--c-bg);
position: relative;
overflow: hidden;
padding: 40px 20px;
}
.fg-08__art-bg {
position: absolute;
inset: 0;
pointer-events: none;
overflow: hidden;
}
.fg-08__orb {
position: absolute;
border-radius: 50%;
filter: blur(70px);
}
.fg-08__orb--1 {
width: 380px;
height: 380px;
background: radial-gradient(circle,rgba(168,85,247,.5),transparent 70%);
top: -80px;
left: -60px;
animation: fg-13-o1 18s ease-in-out infinite alternate;
}
.fg-08__orb--2 {
width: 340px;
height: 340px;
background: radial-gradient(circle,rgba(236,72,153,.45),transparent 70%);
bottom: -60px;
right: -60px;
animation: fg-13-o2 22s ease-in-out infinite alternate;
}
.fg-08__orb--3 {
width: 260px;
height: 260px;
background: radial-gradient(circle,rgba(99,102,241,.35),transparent 70%);
top: 40%;
left: 40%;
animation: fg-13-o3 15s ease-in-out infinite alternate;
}
@keyframes fg-13-o1 {
to {
transform: translate(60px,80px) scale(1.15);
}
}
@keyframes fg-13-o2 {
to {
transform: translate(-50px,-60px) scale(1.1);
}
}
@keyframes fg-13-o3 {
to {
transform: translate(-70px,50px) scale(.9);
}
}
.fg-08__player {
position: relative;
z-index: 1;
width: 100%;
max-width: 360px;
background: var(--c-glass);
backdrop-filter: blur(24px) saturate(180%);
-webkit-backdrop-filter: blur(24px) saturate(180%);
border: 1px solid var(--c-border);
border-radius: 24px;
padding: 24px;
box-shadow: 0 8px 48px rgba(0,0,0,.5),0 1px 0 rgba(255,255,255,.12) inset;
}
.fg-08__disc-wrap {
display: flex;
justify-content: center;
margin-bottom: 22px;
}
.fg-08__disc {
width: 130px;
height: 130px;
border-radius: 50%;
background: conic-gradient(from 0deg,#1a0a2e,#2d1566,#1a0a2e,#0d0820,#2d1566,#1a0a2e);
position: relative;
display: flex;
align-items: center;
justify-content: center;
border: 2px solid rgba(255,255,255,.08);
box-shadow: 0 0 40px rgba(168,85,247,.3),0 0 0 8px rgba(255,255,255,.03);
}
.fg-13.is-playing .fg-08__disc {
animation: fg-13-spin 4s linear infinite;
}
@keyframes fg-13-spin {
to {
transform: rotate(360deg);
}
}
.fg-08__disc-ring {
position: absolute;
border-radius: 50%;
border: 1px solid rgba(255,255,255,.06);
}
.fg-08__disc-ring--1 {
width: 100px;
height: 100px;
}
.fg-08__disc-ring--2 {
width: 72px;
height: 72px;
}
.fg-08__disc-center {
width: 44px;
height: 44px;
border-radius: 50%;
background: radial-gradient(circle,#2a1060,#1a0840);
border: 1px solid rgba(255,255,255,.1);
}
.fg-08__disc-dot {
position: absolute;
width: 8px;
height: 8px;
border-radius: 50%;
background: rgba(255,255,255,.7);
}
.fg-08__info {
display: flex;
flex-direction: column;
gap: 14px;
}
.fg-08__track-row {
display: flex;
align-items: center;
justify-content: space-between;
}
.fg-08__track {
font-size: 17px;
font-weight: 800;
color: var(--c-text);
letter-spacing: -.2px;
margin-bottom: 3px;
}
.fg-08__artist {
font-size: 13px;
color: var(--c-muted);
}
.fg-08__like {
width: 36px;
height: 36px;
border: 1px solid var(--c-border);
border-radius: 50%;
background: rgba(255,255,255,.06);
color: rgba(255,255,255,.6);
cursor: pointer;
display: flex;
align-items: center;
justify-content: center;
transition: background var(--t),transform .15s;
flex-shrink: 0;
}
.fg-08__like:hover {
background: rgba(255,255,255,.12);
transform: scale(1.08);
}
.fg-08__like-f {
display: none;
}
.fg-08__prog-wrap {
display: flex;
flex-direction: column;
gap: 6px;
}
.fg-08__prog-bar {
height: 4px;
border-radius: 2px;
background: rgba(255,255,255,.1);
cursor: pointer;
overflow: hidden;
}
.fg-08__prog-fill {
height: 100%;
width: 0%;
border-radius: 2px;
background: linear-gradient(90deg,var(--c-a),var(--c-a2));
transition: width .5s linear;
box-shadow: 0 0 8px rgba(168,85,247,.5);
}
.fg-13.is-playing .fg-08__prog-fill {
box-shadow: 0 0 12px rgba(168,85,247,.7);
}
.fg-08__times {
display: flex;
justify-content: space-between;
font-size: 11px;
color: var(--c-muted);
}
.fg-08__controls {
display: flex;
align-items: center;
justify-content: space-between;
gap: 8px;
}
.fg-08__ctrl {
border: none;
background: transparent;
color: rgba(255,255,255,.6);
cursor: pointer;
border-radius: 50%;
display: flex;
align-items: center;
justify-content: center;
transition: color var(--t),background var(--t),transform .15s;
}
.fg-08__ctrl:hover {
color: var(--c-text);
transform: scale(1.1);
}
.fg-08__ctrl--sm {
width: 32px;
height: 32px;
}
.fg-08__ctrl:not(.fg-08__ctrl--sm):not(.fg-08__ctrl--play) {
width: 38px;
height: 38px;
background: rgba(255,255,255,.06);
border: 1px solid var(--c-border);
}
.fg-08__ctrl--play {
width: 52px;
height: 52px;
background: linear-gradient(135deg,var(--c-a),var(--c-a2));
color: #fff;
box-shadow: 0 4px 18px rgba(168,85,247,.5);
}
.fg-08__ctrl--play:hover {
transform: scale(1.08);
box-shadow: 0 6px 24px rgba(168,85,247,.65);
}
.fg-08__ctrl.is-active {
color: var(--c-a);
}
.fg-08__vol-wrap {
display: flex;
align-items: center;
gap: 10px;
}
.fg-08__vol-wrap svg {
color: rgba(255,255,255,.4);
flex-shrink: 0;
}
.fg-08__vol-bar {
flex: 1;
height: 3px;
border-radius: 2px;
background: rgba(255,255,255,.1);
}
.fg-08__vol-fill {
width: 70%;
height: 100%;
border-radius: 2px;
background: linear-gradient(90deg,var(--c-a),var(--c-a2));
}
@media (prefers-reduced-motion: reduce) {
.fg-08__orb {
animation: none;
}
.fg-13.is-playing .fg-08__disc {
animation: none;
}
.fg-08__prog-fill,
.fg-08__like,
.fg-08__ctrl {
transition: none;
}
}.fg-13,
.fg-13 *,
.fg-13 *::before,
.fg-13 *::after {
box-sizing: border-box;
margin: 0;
padding: 0;
}
.fg-13 ::selection {
background: rgba(167,139,250,.5);
color: #fff;
}
.fg-13 {
--c-bg: #0d0514;
--c-a: #a855f7;
--c-a2: #ec4899;
--c-glass: rgba(255,255,255,.07);
--c-border: rgba(255,255,255,.12);
--c-text: #f0eeff;
--c-muted: rgba(240,238,255,.5);
--t: .25s ease;
font-family: system-ui,-apple-system,'Segoe UI',sans-serif;
min-height: 100vh;
display: flex;
align-items: center;
justify-content: center;
background: var(--c-bg);
position: relative;
overflow: hidden;
padding: 40px 20px;
}
.fg-08__art-bg {
position: absolute;
inset: 0;
pointer-events: none;
overflow: hidden;
}
.fg-08__orb {
position: absolute;
border-radius: 50%;
filter: blur(70px);
}
.fg-08__orb--1 {
width: 380px;
height: 380px;
background: radial-gradient(circle,rgba(168,85,247,.5),transparent 70%);
top: -80px;
left: -60px;
animation: fg-13-o1 18s ease-in-out infinite alternate;
}
.fg-08__orb--2 {
width: 340px;
height: 340px;
background: radial-gradient(circle,rgba(236,72,153,.45),transparent 70%);
bottom: -60px;
right: -60px;
animation: fg-13-o2 22s ease-in-out infinite alternate;
}
.fg-08__orb--3 {
width: 260px;
height: 260px;
background: radial-gradient(circle,rgba(99,102,241,.35),transparent 70%);
top: 40%;
left: 40%;
animation: fg-13-o3 15s ease-in-out infinite alternate;
}
@keyframes fg-13-o1 {
to {
transform: translate(60px,80px) scale(1.15);
}
}
@keyframes fg-13-o2 {
to {
transform: translate(-50px,-60px) scale(1.1);
}
}
@keyframes fg-13-o3 {
to {
transform: translate(-70px,50px) scale(.9);
}
}
.fg-08__player {
position: relative;
z-index: 1;
width: 100%;
max-width: 360px;
background: var(--c-glass);
backdrop-filter: blur(24px) saturate(180%);
-webkit-backdrop-filter: blur(24px) saturate(180%);
border: 1px solid var(--c-border);
border-radius: 24px;
padding: 24px;
box-shadow: 0 8px 48px rgba(0,0,0,.5),0 1px 0 rgba(255,255,255,.12) inset;
}
.fg-08__disc-wrap {
display: flex;
justify-content: center;
margin-bottom: 22px;
}
.fg-08__disc {
width: 130px;
height: 130px;
border-radius: 50%;
background: conic-gradient(from 0deg,#1a0a2e,#2d1566,#1a0a2e,#0d0820,#2d1566,#1a0a2e);
position: relative;
display: flex;
align-items: center;
justify-content: center;
border: 2px solid rgba(255,255,255,.08);
box-shadow: 0 0 40px rgba(168,85,247,.3),0 0 0 8px rgba(255,255,255,.03);
}
.fg-13.is-playing .fg-08__disc {
animation: fg-13-spin 4s linear infinite;
}
@keyframes fg-13-spin {
to {
transform: rotate(360deg);
}
}
.fg-08__disc-ring {
position: absolute;
border-radius: 50%;
border: 1px solid rgba(255,255,255,.06);
}
.fg-08__disc-ring--1 {
width: 100px;
height: 100px;
}
.fg-08__disc-ring--2 {
width: 72px;
height: 72px;
}
.fg-08__disc-center {
width: 44px;
height: 44px;
border-radius: 50%;
background: radial-gradient(circle,#2a1060,#1a0840);
border: 1px solid rgba(255,255,255,.1);
}
.fg-08__disc-dot {
position: absolute;
width: 8px;
height: 8px;
border-radius: 50%;
background: rgba(255,255,255,.7);
}
.fg-08__info {
display: flex;
flex-direction: column;
gap: 14px;
}
.fg-08__track-row {
display: flex;
align-items: center;
justify-content: space-between;
}
.fg-08__track {
font-size: 17px;
font-weight: 800;
color: var(--c-text);
letter-spacing: -.2px;
margin-bottom: 3px;
}
.fg-08__artist {
font-size: 13px;
color: var(--c-muted);
}
.fg-08__like {
width: 36px;
height: 36px;
border: 1px solid var(--c-border);
border-radius: 50%;
background: rgba(255,255,255,.06);
color: rgba(255,255,255,.6);
cursor: pointer;
display: flex;
align-items: center;
justify-content: center;
transition: background var(--t),transform .15s;
flex-shrink: 0;
}
.fg-08__like:hover {
background: rgba(255,255,255,.12);
transform: scale(1.08);
}
.fg-08__like-f {
display: none;
}
.fg-08__prog-wrap {
display: flex;
flex-direction: column;
gap: 6px;
}
.fg-08__prog-bar {
height: 4px;
border-radius: 2px;
background: rgba(255,255,255,.1);
cursor: pointer;
overflow: hidden;
}
.fg-08__prog-fill {
height: 100%;
width: 0%;
border-radius: 2px;
background: linear-gradient(90deg,var(--c-a),var(--c-a2));
transition: width .5s linear;
box-shadow: 0 0 8px rgba(168,85,247,.5);
}
.fg-13.is-playing .fg-08__prog-fill {
box-shadow: 0 0 12px rgba(168,85,247,.7);
}
.fg-08__times {
display: flex;
justify-content: space-between;
font-size: 11px;
color: var(--c-muted);
}
.fg-08__controls {
display: flex;
align-items: center;
justify-content: space-between;
gap: 8px;
}
.fg-08__ctrl {
border: none;
background: transparent;
color: rgba(255,255,255,.6);
cursor: pointer;
border-radius: 50%;
display: flex;
align-items: center;
justify-content: center;
transition: color var(--t),background var(--t),transform .15s;
}
.fg-08__ctrl:hover {
color: var(--c-text);
transform: scale(1.1);
}
.fg-08__ctrl--sm {
width: 32px;
height: 32px;
}
.fg-08__ctrl:not(.fg-08__ctrl--sm):not(.fg-08__ctrl--play) {
width: 38px;
height: 38px;
background: rgba(255,255,255,.06);
border: 1px solid var(--c-border);
}
.fg-08__ctrl--play {
width: 52px;
height: 52px;
background: linear-gradient(135deg,var(--c-a),var(--c-a2));
color: #fff;
box-shadow: 0 4px 18px rgba(168,85,247,.5);
}
.fg-08__ctrl--play:hover {
transform: scale(1.08);
box-shadow: 0 6px 24px rgba(168,85,247,.65);
}
.fg-08__ctrl.is-active {
color: var(--c-a);
}
.fg-08__vol-wrap {
display: flex;
align-items: center;
gap: 10px;
}
.fg-08__vol-wrap svg {
color: rgba(255,255,255,.4);
flex-shrink: 0;
}
.fg-08__vol-bar {
flex: 1;
height: 3px;
border-radius: 2px;
background: rgba(255,255,255,.1);
}
.fg-08__vol-fill {
width: 70%;
height: 100%;
border-radius: 2px;
background: linear-gradient(90deg,var(--c-a),var(--c-a2));
}
@media (prefers-reduced-motion: reduce) {
.fg-08__orb {
animation: none;
}
.fg-13.is-playing .fg-08__disc {
animation: none;
}
.fg-08__prog-fill,
.fg-08__like,
.fg-08__ctrl {
transition: none;
}
}(function(){
var r=document.querySelector('.fg-13');
if(!r)return;
var tracks=[
{title:'Neon Horizons',artist:'Echo Pulse',dur:'3:47',secs:227},
{title:'Violet Static',artist:'Wavefold',dur:'4:12',secs:252},
{title:'Glass Orbit',artist:'The Prism',dur:'3:28',secs:208}
];
var idx=0,prog=0,playing=false,timer=null;
var playBtn=r.querySelector('#fg-13-play');
var playIcon=r.querySelector('.fg-08__play-icon');
var pauseIcon=r.querySelector('.fg-08__pause-icon');
var trackEl=r.querySelector('#fg-13-track');
var artistEl=r.querySelector('#fg-13-artist');
var durEl=r.querySelector('#fg-13-dur');
var curEl=r.querySelector('#fg-13-cur');
var fillEl=r.querySelector('#fg-13-prog');
var likeBtn=r.querySelector('#fg-13-like');
function fmt(s){return Math.floor(s/60)+':'+(s%60<10?'0':'')+Math.floor(s%60)}
function loadTrack(){
var t=tracks[idx];
trackEl.textContent=t.title;artistEl.textContent=t.artist;
durEl.textContent=t.dur;prog=0;fillEl.style.width='0%';curEl.textContent='0:00';
}
function tick(){
prog=Math.min(prog+100/tracks[idx].secs*.5,100);
fillEl.style.width=prog+'%';
curEl.textContent=fmt(Math.round(prog/100*tracks[idx].secs));
if(prog>=100){clearInterval(timer);playing=false;r.classList.remove('is-playing');playIcon.style.display='';pauseIcon.style.display='none';playBtn.setAttribute('aria-pressed','false')}
}
playBtn.addEventListener('click',function(){
playing=!playing;
if(playing){r.classList.add('is-playing');clearInterval(timer);timer=setInterval(tick,500);playIcon.style.display='none';pauseIcon.style.display=''}
else{r.classList.remove('is-playing');clearInterval(timer);playIcon.style.display='';pauseIcon.style.display='none'}
playBtn.setAttribute('aria-pressed',playing?'true':'false');
});
r.querySelector('#fg-13-next').addEventListener('click',function(){idx=(idx+1)%tracks.length;clearInterval(timer);playing=false;r.classList.remove('is-playing');playIcon.style.display='';pauseIcon.style.display='none';loadTrack()});
r.querySelector('#fg-13-prev').addEventListener('click',function(){idx=(idx-1+tracks.length)%tracks.length;clearInterval(timer);playing=false;r.classList.remove('is-playing');playIcon.style.display='';pauseIcon.style.display='none';loadTrack()});
r.querySelector('#fg-13-shuf').addEventListener('click',function(){this.classList.toggle('is-active')});
r.querySelector('#fg-13-rep').addEventListener('click',function(){this.classList.toggle('is-active')});
likeBtn.addEventListener('click',function(){
var on=likeBtn.classList.toggle('is-liked');
likeBtn.querySelector('.fg-08__like-e').style.display=on?'none':'';
likeBtn.querySelector('.fg-08__like-f').style.display=on?'':'none';
});
})();(function(){
var r=document.querySelector('.fg-13');
if(!r)return;
var tracks=[
{title:'Neon Horizons',artist:'Echo Pulse',dur:'3:47',secs:227},
{title:'Violet Static',artist:'Wavefold',dur:'4:12',secs:252},
{title:'Glass Orbit',artist:'The Prism',dur:'3:28',secs:208}
];
var idx=0,prog=0,playing=false,timer=null;
var playBtn=r.querySelector('#fg-13-play');
var playIcon=r.querySelector('.fg-08__play-icon');
var pauseIcon=r.querySelector('.fg-08__pause-icon');
var trackEl=r.querySelector('#fg-13-track');
var artistEl=r.querySelector('#fg-13-artist');
var durEl=r.querySelector('#fg-13-dur');
var curEl=r.querySelector('#fg-13-cur');
var fillEl=r.querySelector('#fg-13-prog');
var likeBtn=r.querySelector('#fg-13-like');
function fmt(s){return Math.floor(s/60)+':'+(s%60<10?'0':'')+Math.floor(s%60)}
function loadTrack(){
var t=tracks[idx];
trackEl.textContent=t.title;artistEl.textContent=t.artist;
durEl.textContent=t.dur;prog=0;fillEl.style.width='0%';curEl.textContent='0:00';
}
function tick(){
prog=Math.min(prog+100/tracks[idx].secs*.5,100);
fillEl.style.width=prog+'%';
curEl.textContent=fmt(Math.round(prog/100*tracks[idx].secs));
if(prog>=100){clearInterval(timer);playing=false;r.classList.remove('is-playing');playIcon.style.display='';pauseIcon.style.display='none';playBtn.setAttribute('aria-pressed','false')}
}
playBtn.addEventListener('click',function(){
playing=!playing;
if(playing){r.classList.add('is-playing');clearInterval(timer);timer=setInterval(tick,500);playIcon.style.display='none';pauseIcon.style.display=''}
else{r.classList.remove('is-playing');clearInterval(timer);playIcon.style.display='';pauseIcon.style.display='none'}
playBtn.setAttribute('aria-pressed',playing?'true':'false');
});
r.querySelector('#fg-13-next').addEventListener('click',function(){idx=(idx+1)%tracks.length;clearInterval(timer);playing=false;r.classList.remove('is-playing');playIcon.style.display='';pauseIcon.style.display='none';loadTrack()});
r.querySelector('#fg-13-prev').addEventListener('click',function(){idx=(idx-1+tracks.length)%tracks.length;clearInterval(timer);playing=false;r.classList.remove('is-playing');playIcon.style.display='';pauseIcon.style.display='none';loadTrack()});
r.querySelector('#fg-13-shuf').addEventListener('click',function(){this.classList.toggle('is-active')});
r.querySelector('#fg-13-rep').addEventListener('click',function(){this.classList.toggle('is-active')});
likeBtn.addEventListener('click',function(){
var on=likeBtn.classList.toggle('is-liked');
likeBtn.querySelector('.fg-08__like-e').style.display=on?'none':'';
likeBtn.querySelector('.fg-08__like-f').style.display=on?'':'none';
});
})();Here's a working CSS Frosted Glass Effect from CodeFronts. Use it as-is or adapt to your framework. All classes are scoped under a unique prefix so the code won't collide with your existing styles. MIT licensed.
Demo: Glass Music Player UI
Source: https://codefronts.com/design-styles/css-frosted-glass-effect/glass-music-player-ui/
A floating glass music player that blurs a rich purple-coral "album art" gradient behind it. Features a rotating vinyl disc that spins when playing, animated progress bar, track cycling with skip buttons, like toggle, and shuffle/repeat controls.
## HTML
```html
<div class="fg-13">
<div class="fg-08__art-bg" aria-hidden="true">
<div class="fg-08__orb fg-08__orb--1"></div>
<div class="fg-08__orb fg-08__orb--2"></div>
<div class="fg-08__orb fg-08__orb--3"></div>
</div>
<div class="fg-08__player" role="region" aria-label="Music player">
<div class="fg-08__disc-wrap" aria-hidden="true">
<div class="fg-08__disc" id="fg-13-disc">
<div class="fg-08__disc-ring fg-08__disc-ring--1"></div>
<div class="fg-08__disc-ring fg-08__disc-ring--2"></div>
<div class="fg-08__disc-center"></div>
<div class="fg-08__disc-dot"></div>
</div>
</div>
<div class="fg-08__info">
<div class="fg-08__track-row">
<div>
<p class="fg-08__track" id="fg-13-track">Neon Horizons</p>
<p class="fg-08__artist" id="fg-13-artist">Echo Pulse</p>
</div>
<button class="fg-08__like" id="fg-13-like" aria-label="Like track">
<svg class="fg-08__like-e" width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M20.84 4.61a5.5 5.5 0 0 0-7.78 0L12 5.67l-1.06-1.06a5.5 5.5 0 0 0-7.78 7.78l1.06 1.06L12 21.23l7.78-7.78 1.06-1.06a5.5 5.5 0 0 0 0-7.78z"/></svg>
<svg class="fg-08__like-f" width="18" height="18" viewBox="0 0 24 24" fill="#f87171" stroke="#f87171" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M20.84 4.61a5.5 5.5 0 0 0-7.78 0L12 5.67l-1.06-1.06a5.5 5.5 0 0 0-7.78 7.78l1.06 1.06L12 21.23l7.78-7.78 1.06-1.06a5.5 5.5 0 0 0 0-7.78z"/></svg>
</button>
</div>
<div class="fg-08__prog-wrap">
<div class="fg-08__prog-bar" aria-label="Playback progress"><div class="fg-08__prog-fill" id="fg-13-prog"></div></div>
<div class="fg-08__times"><span id="fg-13-cur">0:00</span><span id="fg-13-dur">3:47</span></div>
</div>
<div class="fg-08__controls">
<button class="fg-08__ctrl fg-08__ctrl--sm" id="fg-13-shuf" aria-label="Shuffle" aria-pressed="false">
<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><polyline points="16 3 21 3 21 8"/><line x1="4" y1="20" x2="21" y2="3"/><polyline points="21 16 21 21 16 21"/><line x1="15" y1="15" x2="21" y2="21"/></svg>
</button>
<button class="fg-08__ctrl" id="fg-13-prev" aria-label="Previous track">
<svg width="20" height="20" viewBox="0 0 24 24" fill="currentColor"><polygon points="19 20 9 12 19 4 19 20"/><line x1="5" y1="19" x2="5" y2="5" stroke="currentColor" stroke-width="2" stroke-linecap="round"/></svg>
</button>
<button class="fg-08__ctrl fg-08__ctrl--play" id="fg-13-play" aria-label="Play" aria-pressed="false">
<svg class="fg-08__play-icon" width="22" height="22" viewBox="0 0 24 24" fill="currentColor"><polygon points="5 3 19 12 5 21 5 3"/></svg>
<svg class="fg-08__pause-icon" width="22" height="22" viewBox="0 0 24 24" fill="currentColor" style="display:none"><rect x="6" y="4" width="4" height="16" rx="1"/><rect x="14" y="4" width="4" height="16" rx="1"/></svg>
</button>
<button class="fg-08__ctrl" id="fg-13-next" aria-label="Next track">
<svg width="20" height="20" viewBox="0 0 24 24" fill="currentColor"><polygon points="5 4 15 12 5 20 5 4"/><line x1="19" y1="5" x2="19" y2="19" stroke="currentColor" stroke-width="2" stroke-linecap="round"/></svg>
</button>
<button class="fg-08__ctrl fg-08__ctrl--sm" id="fg-13-rep" aria-label="Repeat" aria-pressed="false">
<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><polyline points="17 1 21 5 17 9"/><path d="M3 11V9a4 4 0 0 1 4-4h14"/><polyline points="7 23 3 19 7 15"/><path d="M21 13v2a4 4 0 0 1-4 4H3"/></svg>
</button>
</div>
<div class="fg-08__vol-wrap" aria-label="Volume">
<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><polygon points="11 5 6 9 2 9 2 15 6 15 11 19 11 5"/><path d="M15.54 8.46a5 5 0 0 1 0 7.07"/><path d="M19.07 4.93a10 10 0 0 1 0 14.14"/></svg>
<div class="fg-08__vol-bar"><div class="fg-08__vol-fill"></div></div>
</div>
</div>
</div>
</div>
```
## CSS
```css
.fg-13,
.fg-13 *,
.fg-13 *::before,
.fg-13 *::after {
box-sizing: border-box;
margin: 0;
padding: 0;
}
.fg-13 ::selection {
background: rgba(167,139,250,.5);
color: #fff;
}
.fg-13 {
--c-bg: #0d0514;
--c-a: #a855f7;
--c-a2: #ec4899;
--c-glass: rgba(255,255,255,.07);
--c-border: rgba(255,255,255,.12);
--c-text: #f0eeff;
--c-muted: rgba(240,238,255,.5);
--t: .25s ease;
font-family: system-ui,-apple-system,'Segoe UI',sans-serif;
min-height: 100vh;
display: flex;
align-items: center;
justify-content: center;
background: var(--c-bg);
position: relative;
overflow: hidden;
padding: 40px 20px;
}
.fg-08__art-bg {
position: absolute;
inset: 0;
pointer-events: none;
overflow: hidden;
}
.fg-08__orb {
position: absolute;
border-radius: 50%;
filter: blur(70px);
}
.fg-08__orb--1 {
width: 380px;
height: 380px;
background: radial-gradient(circle,rgba(168,85,247,.5),transparent 70%);
top: -80px;
left: -60px;
animation: fg-13-o1 18s ease-in-out infinite alternate;
}
.fg-08__orb--2 {
width: 340px;
height: 340px;
background: radial-gradient(circle,rgba(236,72,153,.45),transparent 70%);
bottom: -60px;
right: -60px;
animation: fg-13-o2 22s ease-in-out infinite alternate;
}
.fg-08__orb--3 {
width: 260px;
height: 260px;
background: radial-gradient(circle,rgba(99,102,241,.35),transparent 70%);
top: 40%;
left: 40%;
animation: fg-13-o3 15s ease-in-out infinite alternate;
}
@keyframes fg-13-o1 {
to {
transform: translate(60px,80px) scale(1.15);
}
}
@keyframes fg-13-o2 {
to {
transform: translate(-50px,-60px) scale(1.1);
}
}
@keyframes fg-13-o3 {
to {
transform: translate(-70px,50px) scale(.9);
}
}
.fg-08__player {
position: relative;
z-index: 1;
width: 100%;
max-width: 360px;
background: var(--c-glass);
backdrop-filter: blur(24px) saturate(180%);
-webkit-backdrop-filter: blur(24px) saturate(180%);
border: 1px solid var(--c-border);
border-radius: 24px;
padding: 24px;
box-shadow: 0 8px 48px rgba(0,0,0,.5),0 1px 0 rgba(255,255,255,.12) inset;
}
.fg-08__disc-wrap {
display: flex;
justify-content: center;
margin-bottom: 22px;
}
.fg-08__disc {
width: 130px;
height: 130px;
border-radius: 50%;
background: conic-gradient(from 0deg,#1a0a2e,#2d1566,#1a0a2e,#0d0820,#2d1566,#1a0a2e);
position: relative;
display: flex;
align-items: center;
justify-content: center;
border: 2px solid rgba(255,255,255,.08);
box-shadow: 0 0 40px rgba(168,85,247,.3),0 0 0 8px rgba(255,255,255,.03);
}
.fg-13.is-playing .fg-08__disc {
animation: fg-13-spin 4s linear infinite;
}
@keyframes fg-13-spin {
to {
transform: rotate(360deg);
}
}
.fg-08__disc-ring {
position: absolute;
border-radius: 50%;
border: 1px solid rgba(255,255,255,.06);
}
.fg-08__disc-ring--1 {
width: 100px;
height: 100px;
}
.fg-08__disc-ring--2 {
width: 72px;
height: 72px;
}
.fg-08__disc-center {
width: 44px;
height: 44px;
border-radius: 50%;
background: radial-gradient(circle,#2a1060,#1a0840);
border: 1px solid rgba(255,255,255,.1);
}
.fg-08__disc-dot {
position: absolute;
width: 8px;
height: 8px;
border-radius: 50%;
background: rgba(255,255,255,.7);
}
.fg-08__info {
display: flex;
flex-direction: column;
gap: 14px;
}
.fg-08__track-row {
display: flex;
align-items: center;
justify-content: space-between;
}
.fg-08__track {
font-size: 17px;
font-weight: 800;
color: var(--c-text);
letter-spacing: -.2px;
margin-bottom: 3px;
}
.fg-08__artist {
font-size: 13px;
color: var(--c-muted);
}
.fg-08__like {
width: 36px;
height: 36px;
border: 1px solid var(--c-border);
border-radius: 50%;
background: rgba(255,255,255,.06);
color: rgba(255,255,255,.6);
cursor: pointer;
display: flex;
align-items: center;
justify-content: center;
transition: background var(--t),transform .15s;
flex-shrink: 0;
}
.fg-08__like:hover {
background: rgba(255,255,255,.12);
transform: scale(1.08);
}
.fg-08__like-f {
display: none;
}
.fg-08__prog-wrap {
display: flex;
flex-direction: column;
gap: 6px;
}
.fg-08__prog-bar {
height: 4px;
border-radius: 2px;
background: rgba(255,255,255,.1);
cursor: pointer;
overflow: hidden;
}
.fg-08__prog-fill {
height: 100%;
width: 0%;
border-radius: 2px;
background: linear-gradient(90deg,var(--c-a),var(--c-a2));
transition: width .5s linear;
box-shadow: 0 0 8px rgba(168,85,247,.5);
}
.fg-13.is-playing .fg-08__prog-fill {
box-shadow: 0 0 12px rgba(168,85,247,.7);
}
.fg-08__times {
display: flex;
justify-content: space-between;
font-size: 11px;
color: var(--c-muted);
}
.fg-08__controls {
display: flex;
align-items: center;
justify-content: space-between;
gap: 8px;
}
.fg-08__ctrl {
border: none;
background: transparent;
color: rgba(255,255,255,.6);
cursor: pointer;
border-radius: 50%;
display: flex;
align-items: center;
justify-content: center;
transition: color var(--t),background var(--t),transform .15s;
}
.fg-08__ctrl:hover {
color: var(--c-text);
transform: scale(1.1);
}
.fg-08__ctrl--sm {
width: 32px;
height: 32px;
}
.fg-08__ctrl:not(.fg-08__ctrl--sm):not(.fg-08__ctrl--play) {
width: 38px;
height: 38px;
background: rgba(255,255,255,.06);
border: 1px solid var(--c-border);
}
.fg-08__ctrl--play {
width: 52px;
height: 52px;
background: linear-gradient(135deg,var(--c-a),var(--c-a2));
color: #fff;
box-shadow: 0 4px 18px rgba(168,85,247,.5);
}
.fg-08__ctrl--play:hover {
transform: scale(1.08);
box-shadow: 0 6px 24px rgba(168,85,247,.65);
}
.fg-08__ctrl.is-active {
color: var(--c-a);
}
.fg-08__vol-wrap {
display: flex;
align-items: center;
gap: 10px;
}
.fg-08__vol-wrap svg {
color: rgba(255,255,255,.4);
flex-shrink: 0;
}
.fg-08__vol-bar {
flex: 1;
height: 3px;
border-radius: 2px;
background: rgba(255,255,255,.1);
}
.fg-08__vol-fill {
width: 70%;
height: 100%;
border-radius: 2px;
background: linear-gradient(90deg,var(--c-a),var(--c-a2));
}
@media (prefers-reduced-motion: reduce) {
.fg-08__orb {
animation: none;
}
.fg-13.is-playing .fg-08__disc {
animation: none;
}
.fg-08__prog-fill,
.fg-08__like,
.fg-08__ctrl {
transition: none;
}
}
```
## JavaScript
```js
(function(){
var r=document.querySelector('.fg-13');
if(!r)return;
var tracks=[
{title:'Neon Horizons',artist:'Echo Pulse',dur:'3:47',secs:227},
{title:'Violet Static',artist:'Wavefold',dur:'4:12',secs:252},
{title:'Glass Orbit',artist:'The Prism',dur:'3:28',secs:208}
];
var idx=0,prog=0,playing=false,timer=null;
var playBtn=r.querySelector('#fg-13-play');
var playIcon=r.querySelector('.fg-08__play-icon');
var pauseIcon=r.querySelector('.fg-08__pause-icon');
var trackEl=r.querySelector('#fg-13-track');
var artistEl=r.querySelector('#fg-13-artist');
var durEl=r.querySelector('#fg-13-dur');
var curEl=r.querySelector('#fg-13-cur');
var fillEl=r.querySelector('#fg-13-prog');
var likeBtn=r.querySelector('#fg-13-like');
function fmt(s){return Math.floor(s/60)+':'+(s%60<10?'0':'')+Math.floor(s%60)}
function loadTrack(){
var t=tracks[idx];
trackEl.textContent=t.title;artistEl.textContent=t.artist;
durEl.textContent=t.dur;prog=0;fillEl.style.width='0%';curEl.textContent='0:00';
}
function tick(){
prog=Math.min(prog+100/tracks[idx].secs*.5,100);
fillEl.style.width=prog+'%';
curEl.textContent=fmt(Math.round(prog/100*tracks[idx].secs));
if(prog>=100){clearInterval(timer);playing=false;r.classList.remove('is-playing');playIcon.style.display='';pauseIcon.style.display='none';playBtn.setAttribute('aria-pressed','false')}
}
playBtn.addEventListener('click',function(){
playing=!playing;
if(playing){r.classList.add('is-playing');clearInterval(timer);timer=setInterval(tick,500);playIcon.style.display='none';pauseIcon.style.display=''}
else{r.classList.remove('is-playing');clearInterval(timer);playIcon.style.display='';pauseIcon.style.display='none'}
playBtn.setAttribute('aria-pressed',playing?'true':'false');
});
r.querySelector('#fg-13-next').addEventListener('click',function(){idx=(idx+1)%tracks.length;clearInterval(timer);playing=false;r.classList.remove('is-playing');playIcon.style.display='';pauseIcon.style.display='none';loadTrack()});
r.querySelector('#fg-13-prev').addEventListener('click',function(){idx=(idx-1+tracks.length)%tracks.length;clearInterval(timer);playing=false;r.classList.remove('is-playing');playIcon.style.display='';pauseIcon.style.display='none';loadTrack()});
r.querySelector('#fg-13-shuf').addEventListener('click',function(){this.classList.toggle('is-active')});
r.querySelector('#fg-13-rep').addEventListener('click',function(){this.classList.toggle('is-active')});
likeBtn.addEventListener('click',function(){
var on=likeBtn.classList.toggle('is-liked');
likeBtn.querySelector('.fg-08__like-e').style.display=on?'none':'';
likeBtn.querySelector('.fg-08__like-f').style.display=on?'':'none';
});
})();
```Here's a working CSS Frosted Glass Effect from CodeFronts. Use it as-is or adapt to your framework. All classes are scoped under a unique prefix so the code won't collide with your existing styles. MIT licensed.
Demo: Glass Music Player UI
Source: https://codefronts.com/design-styles/css-frosted-glass-effect/glass-music-player-ui/
A floating glass music player that blurs a rich purple-coral "album art" gradient behind it. Features a rotating vinyl disc that spins when playing, animated progress bar, track cycling with skip buttons, like toggle, and shuffle/repeat controls.
## HTML
```html
<div class="fg-13">
<div class="fg-08__art-bg" aria-hidden="true">
<div class="fg-08__orb fg-08__orb--1"></div>
<div class="fg-08__orb fg-08__orb--2"></div>
<div class="fg-08__orb fg-08__orb--3"></div>
</div>
<div class="fg-08__player" role="region" aria-label="Music player">
<div class="fg-08__disc-wrap" aria-hidden="true">
<div class="fg-08__disc" id="fg-13-disc">
<div class="fg-08__disc-ring fg-08__disc-ring--1"></div>
<div class="fg-08__disc-ring fg-08__disc-ring--2"></div>
<div class="fg-08__disc-center"></div>
<div class="fg-08__disc-dot"></div>
</div>
</div>
<div class="fg-08__info">
<div class="fg-08__track-row">
<div>
<p class="fg-08__track" id="fg-13-track">Neon Horizons</p>
<p class="fg-08__artist" id="fg-13-artist">Echo Pulse</p>
</div>
<button class="fg-08__like" id="fg-13-like" aria-label="Like track">
<svg class="fg-08__like-e" width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M20.84 4.61a5.5 5.5 0 0 0-7.78 0L12 5.67l-1.06-1.06a5.5 5.5 0 0 0-7.78 7.78l1.06 1.06L12 21.23l7.78-7.78 1.06-1.06a5.5 5.5 0 0 0 0-7.78z"/></svg>
<svg class="fg-08__like-f" width="18" height="18" viewBox="0 0 24 24" fill="#f87171" stroke="#f87171" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M20.84 4.61a5.5 5.5 0 0 0-7.78 0L12 5.67l-1.06-1.06a5.5 5.5 0 0 0-7.78 7.78l1.06 1.06L12 21.23l7.78-7.78 1.06-1.06a5.5 5.5 0 0 0 0-7.78z"/></svg>
</button>
</div>
<div class="fg-08__prog-wrap">
<div class="fg-08__prog-bar" aria-label="Playback progress"><div class="fg-08__prog-fill" id="fg-13-prog"></div></div>
<div class="fg-08__times"><span id="fg-13-cur">0:00</span><span id="fg-13-dur">3:47</span></div>
</div>
<div class="fg-08__controls">
<button class="fg-08__ctrl fg-08__ctrl--sm" id="fg-13-shuf" aria-label="Shuffle" aria-pressed="false">
<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><polyline points="16 3 21 3 21 8"/><line x1="4" y1="20" x2="21" y2="3"/><polyline points="21 16 21 21 16 21"/><line x1="15" y1="15" x2="21" y2="21"/></svg>
</button>
<button class="fg-08__ctrl" id="fg-13-prev" aria-label="Previous track">
<svg width="20" height="20" viewBox="0 0 24 24" fill="currentColor"><polygon points="19 20 9 12 19 4 19 20"/><line x1="5" y1="19" x2="5" y2="5" stroke="currentColor" stroke-width="2" stroke-linecap="round"/></svg>
</button>
<button class="fg-08__ctrl fg-08__ctrl--play" id="fg-13-play" aria-label="Play" aria-pressed="false">
<svg class="fg-08__play-icon" width="22" height="22" viewBox="0 0 24 24" fill="currentColor"><polygon points="5 3 19 12 5 21 5 3"/></svg>
<svg class="fg-08__pause-icon" width="22" height="22" viewBox="0 0 24 24" fill="currentColor" style="display:none"><rect x="6" y="4" width="4" height="16" rx="1"/><rect x="14" y="4" width="4" height="16" rx="1"/></svg>
</button>
<button class="fg-08__ctrl" id="fg-13-next" aria-label="Next track">
<svg width="20" height="20" viewBox="0 0 24 24" fill="currentColor"><polygon points="5 4 15 12 5 20 5 4"/><line x1="19" y1="5" x2="19" y2="19" stroke="currentColor" stroke-width="2" stroke-linecap="round"/></svg>
</button>
<button class="fg-08__ctrl fg-08__ctrl--sm" id="fg-13-rep" aria-label="Repeat" aria-pressed="false">
<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><polyline points="17 1 21 5 17 9"/><path d="M3 11V9a4 4 0 0 1 4-4h14"/><polyline points="7 23 3 19 7 15"/><path d="M21 13v2a4 4 0 0 1-4 4H3"/></svg>
</button>
</div>
<div class="fg-08__vol-wrap" aria-label="Volume">
<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><polygon points="11 5 6 9 2 9 2 15 6 15 11 19 11 5"/><path d="M15.54 8.46a5 5 0 0 1 0 7.07"/><path d="M19.07 4.93a10 10 0 0 1 0 14.14"/></svg>
<div class="fg-08__vol-bar"><div class="fg-08__vol-fill"></div></div>
</div>
</div>
</div>
</div>
```
## CSS
```css
.fg-13,
.fg-13 *,
.fg-13 *::before,
.fg-13 *::after {
box-sizing: border-box;
margin: 0;
padding: 0;
}
.fg-13 ::selection {
background: rgba(167,139,250,.5);
color: #fff;
}
.fg-13 {
--c-bg: #0d0514;
--c-a: #a855f7;
--c-a2: #ec4899;
--c-glass: rgba(255,255,255,.07);
--c-border: rgba(255,255,255,.12);
--c-text: #f0eeff;
--c-muted: rgba(240,238,255,.5);
--t: .25s ease;
font-family: system-ui,-apple-system,'Segoe UI',sans-serif;
min-height: 100vh;
display: flex;
align-items: center;
justify-content: center;
background: var(--c-bg);
position: relative;
overflow: hidden;
padding: 40px 20px;
}
.fg-08__art-bg {
position: absolute;
inset: 0;
pointer-events: none;
overflow: hidden;
}
.fg-08__orb {
position: absolute;
border-radius: 50%;
filter: blur(70px);
}
.fg-08__orb--1 {
width: 380px;
height: 380px;
background: radial-gradient(circle,rgba(168,85,247,.5),transparent 70%);
top: -80px;
left: -60px;
animation: fg-13-o1 18s ease-in-out infinite alternate;
}
.fg-08__orb--2 {
width: 340px;
height: 340px;
background: radial-gradient(circle,rgba(236,72,153,.45),transparent 70%);
bottom: -60px;
right: -60px;
animation: fg-13-o2 22s ease-in-out infinite alternate;
}
.fg-08__orb--3 {
width: 260px;
height: 260px;
background: radial-gradient(circle,rgba(99,102,241,.35),transparent 70%);
top: 40%;
left: 40%;
animation: fg-13-o3 15s ease-in-out infinite alternate;
}
@keyframes fg-13-o1 {
to {
transform: translate(60px,80px) scale(1.15);
}
}
@keyframes fg-13-o2 {
to {
transform: translate(-50px,-60px) scale(1.1);
}
}
@keyframes fg-13-o3 {
to {
transform: translate(-70px,50px) scale(.9);
}
}
.fg-08__player {
position: relative;
z-index: 1;
width: 100%;
max-width: 360px;
background: var(--c-glass);
backdrop-filter: blur(24px) saturate(180%);
-webkit-backdrop-filter: blur(24px) saturate(180%);
border: 1px solid var(--c-border);
border-radius: 24px;
padding: 24px;
box-shadow: 0 8px 48px rgba(0,0,0,.5),0 1px 0 rgba(255,255,255,.12) inset;
}
.fg-08__disc-wrap {
display: flex;
justify-content: center;
margin-bottom: 22px;
}
.fg-08__disc {
width: 130px;
height: 130px;
border-radius: 50%;
background: conic-gradient(from 0deg,#1a0a2e,#2d1566,#1a0a2e,#0d0820,#2d1566,#1a0a2e);
position: relative;
display: flex;
align-items: center;
justify-content: center;
border: 2px solid rgba(255,255,255,.08);
box-shadow: 0 0 40px rgba(168,85,247,.3),0 0 0 8px rgba(255,255,255,.03);
}
.fg-13.is-playing .fg-08__disc {
animation: fg-13-spin 4s linear infinite;
}
@keyframes fg-13-spin {
to {
transform: rotate(360deg);
}
}
.fg-08__disc-ring {
position: absolute;
border-radius: 50%;
border: 1px solid rgba(255,255,255,.06);
}
.fg-08__disc-ring--1 {
width: 100px;
height: 100px;
}
.fg-08__disc-ring--2 {
width: 72px;
height: 72px;
}
.fg-08__disc-center {
width: 44px;
height: 44px;
border-radius: 50%;
background: radial-gradient(circle,#2a1060,#1a0840);
border: 1px solid rgba(255,255,255,.1);
}
.fg-08__disc-dot {
position: absolute;
width: 8px;
height: 8px;
border-radius: 50%;
background: rgba(255,255,255,.7);
}
.fg-08__info {
display: flex;
flex-direction: column;
gap: 14px;
}
.fg-08__track-row {
display: flex;
align-items: center;
justify-content: space-between;
}
.fg-08__track {
font-size: 17px;
font-weight: 800;
color: var(--c-text);
letter-spacing: -.2px;
margin-bottom: 3px;
}
.fg-08__artist {
font-size: 13px;
color: var(--c-muted);
}
.fg-08__like {
width: 36px;
height: 36px;
border: 1px solid var(--c-border);
border-radius: 50%;
background: rgba(255,255,255,.06);
color: rgba(255,255,255,.6);
cursor: pointer;
display: flex;
align-items: center;
justify-content: center;
transition: background var(--t),transform .15s;
flex-shrink: 0;
}
.fg-08__like:hover {
background: rgba(255,255,255,.12);
transform: scale(1.08);
}
.fg-08__like-f {
display: none;
}
.fg-08__prog-wrap {
display: flex;
flex-direction: column;
gap: 6px;
}
.fg-08__prog-bar {
height: 4px;
border-radius: 2px;
background: rgba(255,255,255,.1);
cursor: pointer;
overflow: hidden;
}
.fg-08__prog-fill {
height: 100%;
width: 0%;
border-radius: 2px;
background: linear-gradient(90deg,var(--c-a),var(--c-a2));
transition: width .5s linear;
box-shadow: 0 0 8px rgba(168,85,247,.5);
}
.fg-13.is-playing .fg-08__prog-fill {
box-shadow: 0 0 12px rgba(168,85,247,.7);
}
.fg-08__times {
display: flex;
justify-content: space-between;
font-size: 11px;
color: var(--c-muted);
}
.fg-08__controls {
display: flex;
align-items: center;
justify-content: space-between;
gap: 8px;
}
.fg-08__ctrl {
border: none;
background: transparent;
color: rgba(255,255,255,.6);
cursor: pointer;
border-radius: 50%;
display: flex;
align-items: center;
justify-content: center;
transition: color var(--t),background var(--t),transform .15s;
}
.fg-08__ctrl:hover {
color: var(--c-text);
transform: scale(1.1);
}
.fg-08__ctrl--sm {
width: 32px;
height: 32px;
}
.fg-08__ctrl:not(.fg-08__ctrl--sm):not(.fg-08__ctrl--play) {
width: 38px;
height: 38px;
background: rgba(255,255,255,.06);
border: 1px solid var(--c-border);
}
.fg-08__ctrl--play {
width: 52px;
height: 52px;
background: linear-gradient(135deg,var(--c-a),var(--c-a2));
color: #fff;
box-shadow: 0 4px 18px rgba(168,85,247,.5);
}
.fg-08__ctrl--play:hover {
transform: scale(1.08);
box-shadow: 0 6px 24px rgba(168,85,247,.65);
}
.fg-08__ctrl.is-active {
color: var(--c-a);
}
.fg-08__vol-wrap {
display: flex;
align-items: center;
gap: 10px;
}
.fg-08__vol-wrap svg {
color: rgba(255,255,255,.4);
flex-shrink: 0;
}
.fg-08__vol-bar {
flex: 1;
height: 3px;
border-radius: 2px;
background: rgba(255,255,255,.1);
}
.fg-08__vol-fill {
width: 70%;
height: 100%;
border-radius: 2px;
background: linear-gradient(90deg,var(--c-a),var(--c-a2));
}
@media (prefers-reduced-motion: reduce) {
.fg-08__orb {
animation: none;
}
.fg-13.is-playing .fg-08__disc {
animation: none;
}
.fg-08__prog-fill,
.fg-08__like,
.fg-08__ctrl {
transition: none;
}
}
```
## JavaScript
```js
(function(){
var r=document.querySelector('.fg-13');
if(!r)return;
var tracks=[
{title:'Neon Horizons',artist:'Echo Pulse',dur:'3:47',secs:227},
{title:'Violet Static',artist:'Wavefold',dur:'4:12',secs:252},
{title:'Glass Orbit',artist:'The Prism',dur:'3:28',secs:208}
];
var idx=0,prog=0,playing=false,timer=null;
var playBtn=r.querySelector('#fg-13-play');
var playIcon=r.querySelector('.fg-08__play-icon');
var pauseIcon=r.querySelector('.fg-08__pause-icon');
var trackEl=r.querySelector('#fg-13-track');
var artistEl=r.querySelector('#fg-13-artist');
var durEl=r.querySelector('#fg-13-dur');
var curEl=r.querySelector('#fg-13-cur');
var fillEl=r.querySelector('#fg-13-prog');
var likeBtn=r.querySelector('#fg-13-like');
function fmt(s){return Math.floor(s/60)+':'+(s%60<10?'0':'')+Math.floor(s%60)}
function loadTrack(){
var t=tracks[idx];
trackEl.textContent=t.title;artistEl.textContent=t.artist;
durEl.textContent=t.dur;prog=0;fillEl.style.width='0%';curEl.textContent='0:00';
}
function tick(){
prog=Math.min(prog+100/tracks[idx].secs*.5,100);
fillEl.style.width=prog+'%';
curEl.textContent=fmt(Math.round(prog/100*tracks[idx].secs));
if(prog>=100){clearInterval(timer);playing=false;r.classList.remove('is-playing');playIcon.style.display='';pauseIcon.style.display='none';playBtn.setAttribute('aria-pressed','false')}
}
playBtn.addEventListener('click',function(){
playing=!playing;
if(playing){r.classList.add('is-playing');clearInterval(timer);timer=setInterval(tick,500);playIcon.style.display='none';pauseIcon.style.display=''}
else{r.classList.remove('is-playing');clearInterval(timer);playIcon.style.display='';pauseIcon.style.display='none'}
playBtn.setAttribute('aria-pressed',playing?'true':'false');
});
r.querySelector('#fg-13-next').addEventListener('click',function(){idx=(idx+1)%tracks.length;clearInterval(timer);playing=false;r.classList.remove('is-playing');playIcon.style.display='';pauseIcon.style.display='none';loadTrack()});
r.querySelector('#fg-13-prev').addEventListener('click',function(){idx=(idx-1+tracks.length)%tracks.length;clearInterval(timer);playing=false;r.classList.remove('is-playing');playIcon.style.display='';pauseIcon.style.display='none';loadTrack()});
r.querySelector('#fg-13-shuf').addEventListener('click',function(){this.classList.toggle('is-active')});
r.querySelector('#fg-13-rep').addEventListener('click',function(){this.classList.toggle('is-active')});
likeBtn.addEventListener('click',function(){
var on=likeBtn.classList.toggle('is-liked');
likeBtn.querySelector('.fg-08__like-e').style.display=on?'none':'';
likeBtn.querySelector('.fg-08__like-f').style.display=on?'':'none';
});
})();
```How this works
The background gradient serves as a simulated blurred album art — two animated orbs at opposite corners blend coral and indigo, mimicking a real album artwork blurred with filter: blur() but achieved purely in CSS. The glass player card uses backdrop-filter: blur(24px) over this backdrop. The vinyl disc rotates via animation: fg-13-spin 3s linear infinite set to animation-play-state: paused by default. A JS class toggle switches play state to animation-play-state: running via an .is-playing class on the root element, keeping the animation compositor-driven with no JS frame loop.
The progress bar simulates playback using a setInterval that increments a progress variable every 500 ms. The fill width is updated by direct style.width assignment, and the current time display is formatted as mm:ss by dividing the progress percentage by 100 and multiplying by the track duration. Track skipping swaps the textContent of the track name and artist elements and resets the progress counter — the three demo tracks cycle in a ring so next/prev both wrap around correctly.
Make it yours
- Swap the background colour scheme per track by storing each track object with a
bgproperty (e.g. two CSS colour strings for the orb gradients), then updating--c-o1and--c-o2on the root element viastyle.setPropertyon every track change for a dynamic colour-shift effect. - Replace the vinyl disc with an album art image by setting
background: url('cover.jpg') center/coveron.fg-08__disc— the existingborder-radius: 50%,overflow: hidden, and spin animation all work unchanged. - Add a real volume slider by placing a
<input type=range min=0 max=100 value=70>inside.fg-08__vol-wrapand connecting itsinputevent to a Web Audio APIGainNodeor to an HTML<audio>element'svolumeproperty. - Connect to real audio by adding a hidden
<audio id="fg-13-audio">element, linking itssrcto each track's file URL in the tracks array, and driving the progress bar from theaudio.currentTime / audio.durationratio on thetimeupdateevent instead of the interval. - Add a waveform visualiser behind the progress bar by connecting the
<audio>element to a Web AudioAnalyserNodeand drawing frequency bars onto a<canvas>positioned as anoverflow:hiddenbackdrop inside.fg-08__prog-wrap.
Gotchas — read before shipping
animation-play-state: paused/runningis toggled by a class on the root.fg-13element targeting.fg-13.is-playing .fg-08__disc. This avoids inline style mutations which can conflict with CSS transitions — do not setanimationPlayStatevia JS directly as it bypasses the transition compositing pipeline in some WebKit builds.- The
setIntervalfor progress is cleared and restarted on every play/pause toggle. If the interval fires during therequestAnimationFramecallback queue, it may fire twice in rapid succession on heavy CPU frames — clamp the progress variable toMath.min(progress, 100)before reading to prevent bar overflow. - The disc
border-radius: 50%withoverflow: hiddenclips its children, including the inner ring and centre dot. If you add text (e.g. track number) inside the disc, it will be clipped at the corners — use an absolutely positioned overlay outside the disc div instead.
Browser support
| Chrome | Safari | Firefox | Edge |
|---|---|---|---|
| 94+ | 15+ | 103+ | 94+ |
animation-play-state toggling via CSS class is fully cross-browser. backdrop-filter needs -webkit- prefix in Safari. setInterval-based progress is a simulation only — connect a real audio element for production use.