Circular Progress With Percentage and Glass Effect

Circular Progress With Percentage and Glass Effect
Code Snippet:Glass Progress Ring
Author: Jon Kantner
Published: March 21, 2024
Last Updated: March 22, 2024
Downloads: 65
License: MIT
Edit Code online: View on CodePen
Read More

This code creates a circular progress ring with a percentage display and glass effect. It animates progress. The method `progressInc()` increments progress. It’s helpful for visualizing progress in a stylish way.

You can use this code on any web page to display progress in a visually appealing manner. It enhances user experience by providing a clear indication of ongoing processes. The customizable design allows seamless integration into various projects.

How to Create Circular Progress With Percentage And Glass Effect

1. First of all, load the Google Fonts by adding the following CDN links into the head tag of your HTML document.

<link rel='stylesheet' href='https://fonts.googleapis.com/css2?family=DM+Sans&display=swap'>

2. Set up the basic HTML structure. Create a <main> element to contain your progress ring and a replay button. Inside the <main> element, add an SVG element with a class of “pl” to represent the progress ring. Also, include a <text> element with an ID of “pl-percent” to display the progress percentage.

<main>
	<svg class="pl" viewBox="0 0 270 270" width="270px" height="270px" role="img" aria-labelledby="pl-percent">
		<defs>
			<radialGradient id="glass1" r="1">
				<stop stop-color="hsla(0,0%,100%,0.05)" offset="0.4" />
				<stop stop-color="hsla(0,0%,100%,0.35)" offset="1" />
			</radialGradient>
			<linearGradient id="glass2" x1="0" y1="0" x2="0.75" y2="1">
				<stop stop-color="hsla(0,0%,100%,0.3)" offset="0" />
				<stop stop-color="hsla(0,0%,100%,0.08)" offset="1" />
			</linearGradient>
			<linearGradient id="glass3" x1="0" y1="0" x2="0" y2="1">
				<stop stop-color="hsla(0,0%,100%,0.3)" offset="0" />
				<stop stop-color="hsla(0,0%,100%,0)" offset="0.5" />
			</linearGradient>
			<linearGradient id="glass4" x1="0" y1="0" x2="0" y2="1">
				<stop stop-color="hsla(0,0%,100%,0)" offset="0.6" />
				<stop stop-color="hsla(0,0%,100%,0.3)" offset="1" />
			</linearGradient>
			<radialGradient id="glass5" r="1">
				<stop stop-color="hsla(0,0%,0%,0.2)" offset="0.45" />
				<stop stop-color="hsla(0,0%,0%,0)" offset="0.55" />
			</radialGradient>
			<linearGradient id="glass6" x1="0" y1="0" x2="0" y2="1">
				<stop stop-color="hsla(0,0%,100%,0.15)" offset="0" />
				<stop stop-color="hsla(0,0%,100%,0)" offset="0.3" />
			</linearGradient>
			<linearGradient id="glass7" x1="0" y1="0" x2="0" y2="1">
				<stop stop-color="hsla(0,0%,100%,0)" offset="0.7" />
				<stop stop-color="hsla(0,0%,100%,0.1)" offset="1" />
			</linearGradient>
			<clipPath id="glass8">
				<circle cx="135" cy="135" r="125" />
			</clipPath>
			<filter id="glass-glow">
				<feGaussianBlur in="SourceGraphic" stdDeviation="5" />
			</filter>
			<filter id="glass2-blur">
				<feGaussianBlur in="SourceGraphic" stdDeviation="1.5" />
			</filter>
		</defs>
		<g fill="none">
			<g transform="rotate(-90,135,135)">
				<circle class="pl__ring" r="105" cx="135" cy="135" stroke-dasharray="659.74 659.74" stroke-dashoffset="659.74" stroke-width="40" />
				<g filter="url(#glass-glow)" stroke-linecap="round" stroke-width="4" opacity="0.6">
					<circle class="pl__ring-glow1" r="80" cx="135" cy="135" stroke-dasharray="502.66 502.66" stroke-dashoffset="502.66" />
					<circle class="pl__ring-glow2" r="130" cx="135" cy="135" stroke-dasharray="816.82 816.82" stroke-dashoffset="816.82" />
				</g>
			</g>
			<circle stroke="url(#glass1)" stroke-width="40" r="105" cx="135" cy="135" />
			<circle filter="url(#glass2-blur)" stroke="url(#glass2)" stroke-width="9" r="105" cx="135" cy="135" />
			<circle stroke="url(#glass3)" stroke-width="1" r="109" cx="135" cy="135" />
			<circle stroke="url(#glass4)" stroke-width="1" r="101" cx="135" cy="135" />
			<circle stroke="url(#glass5)" stroke-width="14" r="92" cx="135" cy="135" />
			<circle stroke="url(#glass6)" stroke-width="2" r="86" cx="135" cy="135" />
			<circle stroke="url(#glass7)" stroke-width="4" r="87" cx="135" cy="135" />
			<circle clip-path="url(#glass8)" stroke="hsla(var(--hue),90%,10%,0.1)" stroke-width="4" r="125" cx="135" cy="142" />
		</g>
		<text id="pl-percent" fill="currentcolor" font-size="48" text-anchor="middle" x="135" y="151" data-percent></text>
	</svg>
	<button id="replay" class="btn" type="button" title="Replay">
		<svg class="btn__icon" viewBox="0 0 24 24" width="24px" height="24px" aria-hidden="true">
			<path d="M5 13C5 16.866 8.13401 20 12 20C15.866 20 19 16.866 19 13C19 9.13401 15.866 6 12 6H7M7 6L10 3M7 6L10 9" fill="none" stroke="currentcolor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
		</svg>
	</button>
</main>

3. Define the CSS styles to customize the appearance of the progress ring, button, and overall layout. Utilize CSS variables to control colors, transitions, and other visual properties. Apply animations for smooth transitions and effects.

* {
	border: 0;
	box-sizing: border-box;
	margin: 0;
	padding: 0;
}
:root {
	--hue: 223;
	--bg: hsl(var(--hue),90%,10%);
	--fg: hsl(var(--hue),90%,90%);
	--primary: hsl(var(--hue),90%,50%);
	--trans-dur: 0.3s;
	--trans-timing: cubic-bezier(0.65,0,0.35,1);
	font-size: calc(16px + (24 - 16) * (100vw - 320px) / (2560 - 320));
}

body,
button {
	color: var(--fg);
	font: 1em/1.5 "DM Sans", sans-serif;
}
body {
	background-color: var(--bg);
	display: flex;
	height: 100vh;
	transition:
		background-color var(--trans-dur),
		color var(--trans-dur);
}
main {
	margin: auto;
	text-align: center;
}
svg {
	display: block;
}
.btn {
	background-color: transparent;
	cursor: pointer;
	outline: transparent;
	width: 3em;
	height: 3em;
	transition: opacity 0.15s linear;
	-webkit-tap-highlight-color: #0000;
}
.btn:focus-visible,
.btn:hover {
	opacity: 0.5;
}
.btn__icon {
	width: 100%;
	height: auto;
}
.pl {
	--percent: 0;
	margin-bottom: 1.5em;
	overflow: visible;
	width: 16.875em;
	height: 16.875em;
	user-select: none;
	-webkit-user-select: none;
	-moz-user-select: none;
}
.pl__ring,
.pl__ring-glow1,
.pl__ring-glow2 {
	stroke: var(--primary);
	transition: stroke var(--trans-dur);
}
.pl__ring {
	stroke-dashoffset: calc(659.74px * (1 - var(--percent)));
}
.pl__ring-glow1 {
	stroke-dashoffset: calc(502.66px * (1 - var(--percent)));
}
.pl__ring-glow2 {
	stroke-dashoffset: calc(816.82px * (1 - var(--percent)));
}
.pl[data-complete="false"] {
	animation: fade-slide-in 0.5s var(--trans-timing);
}
.pl[data-complete="false"] + .btn {
	visibility: hidden;
}
.pl[data-complete="true"] + .btn {
	animation: fade-in 0.6s;
}

/* Animations */
@keyframes fade-in {
	from {
		animation-timing-function: steps(1,end);
		opacity: 0;
		visibility: hidden;
	}
	50% {
		animation-timing-function: var(--trans-timing);
		opacity: 0;
		visibility: visible;
	}
	to {
		opacity: 1;
	}
}
@keyframes fade-slide-in {
	from {
		opacity: 0;
		transform: translateY(20%);
	}
	to {
		opacity: 1;
		transform: translateY(0);
	}
}

4. Finally, use the following JavaScript code to add dynamic behavior to the progress ring. Define a class named “GlassProgressRing” to handle the progress ring functionality. Initialize the progress ring and handle progress updates and replay functionality.

window.addEventListener("DOMContentLoaded",() => {
	const gpr = new GlassProgressRing(".pl");
	const replayBtn = document.querySelector("#replay");

	replayBtn?.addEventListener("click",gpr.replay.bind(gpr));
});

class GlassProgressRing {
	complete = false;
	percent = 0;
	startTime = 600;
	timeout = null;

	constructor(el) {
		this.el = document.querySelector(el);

		this.init();
	}
	init() {
		this.toggleComplete();
		this.progressDisplay();
		this.timeout = setTimeout(this.loop.bind(this),this.startTime);
	}
	loop() {
		if (!this.complete) {
			this.progressInc();
			this.timeout = setTimeout(this.loop.bind(this),17);
		}
	}
	progressDisplay() {
		this.el?.style.setProperty("--percent",this.percent);

		const percentText = `${Math.round(this.percent * 100)}%`;
		const percentEl = this.el?.querySelector("[data-percent]");

		if (percentEl) percentEl.innerHTML = percentText;
	}
	progressInc(amount = 0.01) {
		if (this.percent < 1) {
			this.percent += amount;
			this.percent = +this.percent.toFixed(2);
		}
		if (this.percent >= 1) {
			this.percent = 1;
			this.complete = true;
			this.toggleComplete();
		}
		this.progressDisplay();
	}
	replay() {
		if (this.complete) {
			this.complete = false;
			this.percent = 0;
			this.init();
		}
	}
	toggleComplete() {
		this.el?.setAttribute("data-complete",this.complete);
	}
}

That’s all! hopefully, you have successfully created Circular Progress With Percentage and Glass Effect. If you have any questions or suggestions, feel free to comment below.

Leave a Comment

This site uses Akismet to reduce spam. Learn how your comment data is processed.

About CodeHim

Free Web Design Code & Scripts - CodeHim is one of the BEST developer websites that provide web designers and developers with a simple way to preview and download a variety of free code & scripts. All codes published on CodeHim are open source, distributed under OSD-compliant license which grants all the rights to use, study, change and share the software in modified and unmodified form. Before publishing, we test and review each code snippet to avoid errors, but we cannot warrant the full correctness of all content. All trademarks, trade names, logos, and icons are the property of their respective owners... find out more...

Please Rel0ad/PressF5 this page if you can't click the download/preview link

X