Как создать эффект (анимацию) вращения по оси Y объекта формы монеты с помощью СSS?

1,00
р.
Была задумка сделать вращение круга, который по оси Z растягивался б на 20+ px (чтобы видно было толщину, как у ребра монеты), но как только я начал выставлять элементы по оси Z, элементы стали вращаться по совсем другой траектории. Как можно получить вышеописанный эффект с помощью CSS/JS/SVG?

Второй вопрос: сейчас я использую setTimeout из-за того, что мои классы немедленно присваиваются и я вижу поворот по оси Y только 1 раз из 8 загрузок страницы. Как инициализировать поворот через класс без функции setTimeout, чтобы это срабатывало с каждой загрузкой страницы?


document.addEventListener('DOMContentLoaded', function(){ //document.querySelector(".side").classList.add('active') function flipCircle(n){ setTimeout( ()=> {n.classList.add('active')}, 50) } var sides = document.getElementsByClassName("side") for (var i = 0 i < sides.length i++) { flipCircle(sides[i]) } }) @font-face { font-family: 'Digital Numbers' font-style: normal font-weight: 400 src: local('Digital Numbers'), url('https://fonts.cdnfonts.com/15953/DigitalNumbers-Regular.woff') format('woff') } * { margin: 0 padding: 0 box-sizing: border-box } body { width: 100vw height: 100vh overflow: hidden background: #0a0a0a }
.text { position: absolute top: 0 left: 0 width: 100% height: 100% overflow-wrap: break-word word-wrap: break-word } h1 { display: inline font-size: 260px line-height: 290px margin: 0 padding: 0 animation: glow 1.5s ease-in-out infinite font-family: 'Digital Numbers', sans-serif } .flip { margin: calc(50vh - 250px) auto width: 500px height: 500px perspective: 700px } .container { position: relative width: 100% height: 100% }
.side { width: 100% height: 100% position: absolute top:0 left:0 backface-visibility: hidden background-repeat: no-repeat background-size: cover background-position: 50% 50% animation: border-glow 1.5s ease-in-out infinite border: 100px solid black border-radius: 100% transition: transform 30s cubic-bezier(1,.01,1,.5), border 500ms ease-in-out transform-style: preserve-3d }
.shuf-front { background-image: url('https://i.ibb.co/FgBcMfmhuf-771.png') }
.shuf-back { transform: rotateY(180deg) scale(-1, 1) background-image: url('https://i.ibb.co/FgBcMfmhuf-771.png') }
.active { transform: rotateY(calc(-2000 * 360deg)) }
/*rotateX(calc(2000 * 360deg)) */
@keyframes glow { 0%,100%{ text-shadow:0 0 30px red } 25%{ text-shadow:0 0 50px orange } 50%{ text-shadow:0 0 50px forestgreen } 75%{ text-shadow:0 0 50px cyan } }
@keyframes border-glow { 0%,100%{ border: 10px solid red } 25%{ border: 20px solid orange } 50%{ border: 10px solid forestgreen } 75%{ border: 20px solid blue } }
@keyframes wobble { 0%,100%{ transform:rotate3d(1,1,0,40deg) } 25%{ transform:rotate3d(-1,1,0,40deg) } 50%{ transform:rotate3d(-1,-1,0,40deg) } 75%{ transform:rotate3d(1,-1,0,40deg) } }

3

3

3

3

3

3

3

3

3

3

3

3

3

3

3

3

3

3

3

3

3

3

3

3

3

3

3

3

3

3

3

3

3

3

3

3

3

3

3

3

3

3

3

3

3

3

3

3

3

3

3

3

3

3

3

3

3

3

3

3

3

3

3

3

3

3

3

3

3

3

3

3

3

3

3

3

3

3

3

3

3

3

3

3

3

3

3

3

3

3

3

3

3

3

3

3

3

3

3

3

3

3

3

3

3

3

3

3

3

3

3

3

3

3

3

3

3

3

3

3

3

3

3

3

3

3

3

3

3

3

3

3

3

3

3

3

3

3

3

3

3

3

3

3

3

3

3

3

3

3

3

3

3

3

3

3

3





Ответ
Монетка с ребром 👌


.coin { --diameter:200px --thickness:20px --scale:0.75 --period:5s --gradient: linear-gradient(gold 0%, yellow 50%, gold 100%) transform-style: preserve-3d width: var(--diameter) height: var(--diameter) animation: spin var(--period) linear infinite }
.side { position: absolute width: 100% height: 100% border-radius: 50% background-color: gold display: flex align-items: center justify-content: center color: yellow font-size: calc(var(--diameter) * 0.6) font-weight: bold }
.head { transform: translateZ(calc(var(--thickness) / 2)) animation: flip-head var(--period) linear infinite }
.tail { transform: translateZ(calc(0px - var(--thickness) / 2)) rotateY(180deg) animation: flip-tail var(--period) linear infinite }
.edge { position: absolute width: var(--thickness) height: 100% transform: translateX(calc(var(--diameter) / 2)) translateZ(calc(var(--thickness) / 2)) rotateY(90deg) transform-origin: 0 0 background-color: gold background-image: var(--gradient) }
@keyframes spin { 0% { transform: rotateY(0deg) scale(var(--scale)) } 100% { transform: rotateY(360deg) scale(var(--scale)) } }
@keyframes flip-tail { 0% { background-image: var(--gradient) color: transparent } 50% { background-image: none color: yellow } 100% { background-image: var(--gradient) color: transparent } }
@keyframes flip-head { 0% { background-image: none color: yellow } 50% { background-image: var(--gradient) color: transparent } 100% { background-image: none color: yellow } }
$
1


В основе решения идея, реализованная в первом ответе от Andrey Fedorov — плавная анимация вращения вокруг оси Y, и пошаговая смена фона.
Однако, если смотреть на объект строго в направлении оси Z, то можно добиться иллюзии объема за счет синхронного вращения двух скругленных плоскостей и вертикального прямоугольника ("ребра"), проходящего через центры кругов под углом 90 градусов. Ширина прямоугольника должна быть равна расстоянию между кругами по оси Z.
При вращении дальний от наблюдателя круг принимает цвет ребра и незаметно сливается с ним в положениях, близких к 90 и 270 градусам. Одинаковая градиентная заливка ребра и дальнего круга усиливает эффект, создавая иллюзию кривизны поверхности.

👇 Ниже схематическая анимация с полупрозрачными элементами:


.coin { --diameter:200px --thickness:20px --scale:0.75 --period:5s --gradient: linear-gradient(blue 0%, blue 100%) transform-style: preserve-3d width: var(--diameter) height: var(--diameter) animation: spin var(--period) linear infinite }
.side { opacity:0.75 position: absolute width: 100% height: 100% border-radius: 50% background-color: red display: flex align-items: center justify-content: center color: transparent font-size: calc(var(--diameter) * 0.6) }
.head { transform: translateZ(calc(var(--thickness) / 2)) animation: flip-head var(--period) linear infinite }
.tail { transform: translateZ(calc(0px - var(--thickness) / 2)) rotateY(180deg) animation: flip-tail var(--period) linear infinite }
.edge { opacity:0.75 position: absolute width: var(--thickness) height: 100% transform: translateX(calc(var(--diameter) / 2)) translateZ(calc(var(--thickness) / 2)) rotateY(90deg) transform-origin: 0 0 background-color: gold background-image: var(--gradient) }
@keyframes spin { 0% { transform: rotateY(0deg) scale(var(--scale)) } 100% { transform: rotateY(360deg) scale(var(--scale)) } }
@keyframes flip-tail { 0% { background-image: var(--gradient) color: transparent } 50% { background-image: none color: green } 100% { background-image: var(--gradient) color: transparent } }
@keyframes flip-head { 0% { background-image: none color: green } 50% { background-image: var(--gradient) color: transparent } 100% { background-image: none color: green } }
$
1