Creating Adaptive Dot Progress Bars with CSS Gradients and SVG

The article shows how to replace numerous HTML elements with a single CSS‑gradient background tile to build a fully responsive progress bar composed of small dots, explains the calculation of tile size using CSS variables, adds current progress with a linear‑gradient overlay, and offers an SVG alternative that can also be applied to custom range sliders.

Full-Stack Cultivation Path
Full-Stack Cultivation Path
Full-Stack Cultivation Path
Creating Adaptive Dot Progress Bars with CSS Gradients and SVG

Minimal Tile Unit

The repeatable unit for the dot pattern is the C shape that spans the container when its ends are connected. Designing a tile that contains a single dot and the surrounding space allows the background to be tiled across the whole bar.

Radial Gradient Tile

A radial gradient that transitions from white to transparent creates the dot:

.progress {
  background: radial-gradient(circle at 8px 50%, #fff 2px, transparent 2px) #ccc;
}

By default the background size is 100%, so only one dot appears. Define the step size and tile the dots evenly:

.progress {
  --total: 10; /* number of steps */
  --step: calc((100% - 16px) / (var(--total) - 1));
  background-size: var(--step) 100%;
}

Changing --total automatically updates the number of dots.

Adaptive SVG Alternative

For developers who find the radial‑gradient syntax cumbersome, an inline SVG can be used as a data‑URI background. The SVG defines a 2 px white circle at the centre:

<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
  <circle cx="8" cy="8" r="2" fill="white"/>
</svg>

After changing the width/height to 100% and removing viewBox, embed the SVG directly in CSS:

.progress {
  background: url("data:image/svg+xml,%3Csvg fill='none' xmlns='http://www.w3.org/2000/svg'%3E%3Ccircle cx='8' cy='8' r='2' fill='%23fff'/%3E%3C/svg%3E") #ccc;
  background-size: var(--step) 100%;
}

Adding Current Progress

The current step is represented by a CSS variable --progress. A linear‑gradient overlay paints the filled portion, while a pseudo‑element marks the active dot.

.progress {
  --progress: 3; /* active step */
  background: radial-gradient(circle at 8px 50%, #fff 2px, transparent 2px) 0 / var(--step) 100%,
              linear-gradient(#FF5E1A, #FF5E1A) 0 / calc((var(--progress) - 1) * var(--step) + 8px) 100% no-repeat #ccc;
}
.progress::after {
  content: '';
  position: absolute;
  width: 16px;
  height: 16px;
  border: 1px solid #fff;
  background-color: #FF5E1A;
  left: calc((var(--progress) - 1) * var(--step));
  transition: 0.3s;
}

Applying to a Custom Range Slider

The same gradient technique can style the track and thumb of an input type="range". Define --total, --step, and --progress on the range element so the slider visually reflects the number of steps.

[type="range"] {
  --total: 20;
  --progress: 3;
  --step: calc((100% - 16px) / (var(--total) - 1));
  -webkit-appearance: none;
  appearance: none;
  width: 300px;
  height: 16px;
  background: radial-gradient(circle at 8px 8px, #fff 2px, transparent 2px) 0 / var(--step) 100%,
              linear-gradient(#FF5E1A, #FF5E1A) 0 / calc((var(--progress) - 1) * var(--step) + 8px) 100% no-repeat #ccc;
}

[type="range"]::-webkit-slider-runnable-track {
  height: 100%;
  position: relative;
  border-radius: 16px;
  background: radial-gradient(circle at 8px 8px, #fff 2px, transparent 2px) 0 / var(--step) 100%,
              linear-gradient(#FF5E1A, #FF5E1A) 0 / calc((var(--progress) - 1) * var(--step) + 8px) 100% no-repeat #ccc;
}

[type="range"]::-webkit-slider-thumb {
  -webkit-appearance: none;
  width: 16px;
  height: 16px;
  border: 1px solid #fff;
  background-color: #FF5E1A;
  border-radius: 16px;
}

Update --progress on input events:

<input type="range" oninput="this.style.setProperty('--progress', this.value);">

Conclusion

CSS gradients provide a compact, scalable way to render decorative dot patterns without extra markup. By leveraging CSS variables, the same approach adapts to different counts, shows current progress, and can be reused with SVG data‑URIs or custom range sliders.

Reference: "不一样的SVG!SVG在CSS背景平铺中的应用" – 前端侦探
Progress bar example
Progress bar example
Minimal tile unit
Minimal tile unit
Radial gradient illustration
Radial gradient illustration
Resulting dot pattern
Resulting dot pattern
Adjusted background size
Adjusted background size
Variable‑driven dot count
Variable‑driven dot count
Progress overlay
Progress overlay
Current dot indicator
Current dot indicator
Demo animation
Demo animation
Slider demo
Slider demo
Slider interaction
Slider interaction
Original Source

Signed-in readers can open the original source through BestHub's protected redirect.

Sign in to view source
Republication Notice

This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactadmin@besthub.devand we will review it promptly.

SVGCSSHTMLResponsiveGradientsSlider
Full-Stack Cultivation Path
Written by

Full-Stack Cultivation Path

Focused on sharing practical tech content about TypeScript, Vue 3, front-end architecture, and source code analysis.

0 followers
Reader feedback

How this landed with the community

Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.