3-dot loader with animated background gradient

by PhilQ

HTML

<div class="wrapper">
<div class="animate-bg-gradient cut-out-dots2">
  <!-- <div class="circle"></div> -->
	<!-- <div class="circle"></div> -->
	<!-- <div class="circle"></div> -->
</div>
</div>

CSS

html, body { width: 100%; height: 100%; margin: 0; padding: 0; }
body {
	display: flex;
	align-items: center;
	justify-content: center;
}

.wrapper {
	border: 0px solid red;
}

.animate-bg-gradient {
	--color1: #ccc;
	--color2: #3e78cf;
	--nr-dots: 3;
	--dot-size: 20;
	--space-in-dots: 0.5;
	--width-in-dots: calc(var(--nr-dots) + (var(--nr-dots) - 1) * var(--space-in-dots));
	--mask-width-in-element-percentage: calc((1 + var(--space-in-dots)) * (100% / var(--width-in-dots)));
	--mask-100-in-dots: calc(var(--width-in-dots) - (1 + var(--space-in-dots)));
	--shift-left-in-mask-position-percentage: calc(-100% * 0.5 * var(--space-in-dots) / var(--mask-100-in-dots));
	--antialias-width: 1;
	--antialias-percentage: calc(var(--antialias-width) / (0.5 * var(--dot-size)));
	--antialias-edge-percentage: calc(100% * (1 - var(--antialias-percentage)));
	
	height: calc(var(--dot-size) * 1px);
	width: calc(var(--dot-size) * var(--width-in-dots) * 1px);

	background-image: linear-gradient(
	  to right,
		var(--color1),
		var(--color1),
		/**/
		var(--color2),
		var(--color2),
		/**/
		var(--color1),
		var(--color1),
		var(--color1),
		var(--color1)
	);
	/* background x size = (nr_of_colorstops - 1) * 100%   */
	background-size: 700% 100%;
	background-position: 0 0;
	background-repeat: no-repeat;
	animation: bg-scroll 2s linear infinite;
}

.cut-out-dots2 {
	/*
		The element contains 3 dots with a half-dot spacing in between them.
		
		So, the element should be:
			height: dot_size
			width: dot_size * (nr_of_dots + (nr_of_dots - 1) * 0.5)
		
		The dots are black circles (`radial-gradient`) in a repeating `mask-image`, being used as an alpha mask.
	*/
	-webkit-mask-mode: alpha;
	-webkit-mask-repeat: repeat-x;
	
	/*
		The mask-image should repeat after 1.5 * dot_size (dot + spacing).
		So, one mask-image width is:
			1.5 * (100% / (nr_of_dots + (nr_of_dots - 1) * 0.5))
	  In this case:
		  1.5 * (100% / 4) = 37.5%
		
		So, the mask-image size is:
			height: 100%
			width:...