<div class="pl">
	<div class="pl__sphere"></div>
	<span class="pl__sphere-shadow"></span>
	<div class="pl__sphere"></div>
	<span class="pl__sphere-shadow"></span>
	<div class="pl__sphere"></div>
	<span class="pl__sphere-shadow"></span>
	<div class="pl__sphere"></div>
	<span class="pl__sphere-shadow"></span>
</div>
// Mixins
@mixin moveFilter($brightness,$blur)
	filter: brightness($brightness) blur($blur)
	-webkit-filter: brightness($brightness) blur($blur)
@mixin sphere($color)
	background: lighten($color,15%)
	box-shadow: 0 -0.75em 0.5em $color inset, 0 0 0.5em fade-out(lighten($color,10%),0.3)
// Normal styles
$sphereDiam: 2em
$spaceBetween: 1em
$sphereCount: 4
$xGridOffset: 0.5em
$animDur: 2s
*
	border: 0
	box-sizing: border-box
	margin: 0
	padding: 0
\:root
	font-size: calc(16px + (32 - 16) * (100vw - 320px) / (1280 - 320))
body
	font: 1em/1.5 sans-serif
	height: 100vh
.pl
	background: linear-gradient(rgb(4,23,73) calc(50% + 1.5em),rgb(6,39,121) calc(50% + 2.5em) calc(50% + 10.5em), rgb(4,23,73))
	position: relative
	overflow: hidden
	perspective: 800px
	transform-style: preserve-3d
	&, &:before
		width: 100%
		height: 100%
	&:before, &__sphere, &__sphere-shadow
		position: absolute
	&:before, &__sphere-shadow
		display: block
	&:before
		background: linear-gradient(rgb(6,39,121),rgba(6,39,121,0)), radial-gradient(100% 100% at 50% 50%,rgba(6,39,121,0) 37.5%,rgb(6,39,121) 50%), repeating-linear-gradient(0deg,rgba(8,55,170,0) 0 0.95em,rgb(8,55,170) 0.95em 1em), repeating-linear-gradient(90deg,rgba(8,55,170,0) 0 0.9em,rgb(8,55,170) 0.9em 1em) $xGridOffset 0
		content: ""
		top: 50%
		left: 50%
		transform: translate(-50%,-50%) rotateX(90deg) translateZ(-4em)
		width: 34em
		height: 34em
	&__sphere
		animation-name: moveSphere
		@include sphere(hsl(223,90%,55%))
		transform: translateZ(10em)
		&, &-shadow
			animation:
				duration: $animDur
				timing-function: ease-in-out
				iteration-count: infinite
			border-radius: 50%
			top: calc(50% - #{$sphereDiam / 2})
			left: calc(50% - #{$sphereDiam / 2})
			width: $sphereDiam
			height: $sphereDiam
			z-index: 1
		&-shadow
			animation-name: moveSphereShadow
			background-image: radial-gradient(100% 100% at center,rgba(0,0,0,0.2) 45%,rgba(0,0,0,0) 50%)
			transform: translateY(4em) translateZ(10em) rotateX(90deg)
		@for $s from 1 through $sphereCount
			&:nth-of-type(#{$s}), &-shadow:nth-of-type(#{$s})
				left: calc(50% - #{($sphereDiam + $spaceBetween) * (($sphereCount - ($s - 1)) - ($sphereCount / 2)) - ($spaceBetween / 2)})
				@if $s > 1
					animation-delay: ($animDur * 0.05) * ($s - 1)
// Animations
@keyframes moveSphere
	from, to
		@include moveFilter(100%,0)
		transform: translateZ(10em)
	25%, 75%
		@include moveFilter(100%,0)
		transform: translateZ(12em)
	50%
		@include moveFilter(80%,4px)
		transform: translateZ(-10em)
@keyframes moveSphereShadow
	from, to
		transform: translateY(4em) translateZ(10em) rotateX(90deg)
	25%, 75%
		transform: translateY(4em) translateZ(12em) rotateX(90deg)
	50%
		transform: translateY(4em) translateZ(-10em) rotateX(90deg)
View Compiled

External CSS

This Pen doesn't use any external CSS resources.

External JavaScript

This Pen doesn't use any external JavaScript resources.