Playing around with CSS variables, animations & transforms to create infinite loop.
Original motion design by Gal Shir https://dribbble.com/shots/3195071-Domino
A Pen by James Warren on CodePen.
Playing around with CSS variables, animations & transforms to create infinite loop.
Original motion design by Gal Shir https://dribbble.com/shots/3195071-Domino
A Pen by James Warren on CodePen.
<div class="settings"> | |
<h3>Scale</h3> | |
<button class="settings__scale is-active" onclick="changeScale(1, this)">1</button> | |
<button class="settings__scale" onclick="changeScale(.5, this)">.5</button> | |
<button class="settings__scale" onclick="changeScale(.25, this)">.25</button> | |
<button class="settings__scale" onclick="changeScale(.1, this)">.1</button> | |
<h3>Duration</h3> | |
<button class="settings__duration" onclick="changeDuration('.7s', this)">.7s</button> | |
<button class="settings__duration is-active" onclick="changeDuration('.5s', this)">.5s</button> | |
<button class="settings__duration" onclick="changeDuration('.3s', this)">.3s</button> | |
</div> | |
<div> | |
<div id="container" class="container"> | |
<section class="stage"> | |
<div class="domino"> | |
<figure class="domino__top"></figure> | |
<figure class="domino__front"></figure> | |
<figure class="domino__bottom"></figure> | |
<figure class="domino__left"></figure> | |
</div> | |
<div class="domino"> | |
<figure class="domino__top"></figure> | |
<figure class="domino__front"></figure> | |
<figure class="domino__bottom"></figure> | |
<figure class="domino__left"></figure> | |
<figure class="domino__shadow"></figure> | |
</div> | |
<div class="domino"> | |
<figure class="domino__top"></figure> | |
<figure class="domino__front"></figure> | |
<figure class="domino__bottom"></figure> | |
<figure class="domino__left"></figure> | |
<figure class="domino__shadow"></figure> | |
</div> | |
<div class="domino"> | |
<figure class="domino__top"></figure> | |
<figure class="domino__front"></figure> | |
<figure class="domino__bottom"></figure> | |
<figure class="domino__left"></figure> | |
<figure class="domino__shadow"></figure> | |
</div> | |
<div class="domino"> | |
<figure class="domino__top"></figure> | |
<figure class="domino__front"></figure> | |
<figure class="domino__bottom"></figure> | |
<figure class="domino__left"></figure> | |
<figure class="domino__shadow"></figure> | |
</div> | |
<div class="domino"> | |
<figure class="domino__top"></figure> | |
<figure class="domino__front"></figure> | |
<figure class="domino__bottom"></figure> | |
<figure class="domino__left"></figure> | |
<figure class="domino__shadow"></figure> | |
</div> | |
<div class="domino"> | |
<figure class="domino__top"></figure> | |
<figure class="domino__front"></figure> | |
<figure class="domino__bottom"></figure> | |
<figure class="domino__left"></figure> | |
<figure class="domino__shadow"></figure> | |
</div> | |
<div class="domino"> | |
<figure class="domino__top"></figure> | |
<figure class="domino__front"></figure> | |
<figure class="domino__bottom"></figure> | |
<figure class="domino__left"></figure> | |
<figure class="domino__shadow"></figure> | |
</div> | |
<div class="domino"> | |
<figure class="domino__top"></figure> | |
<figure class="domino__front"></figure> | |
<figure class="domino__bottom"></figure> | |
<figure class="domino__left"></figure> | |
<figure class="domino__shadow"></figure> | |
</div> | |
<div class="domino"> | |
<figure class="domino__top"></figure> | |
<figure class="domino__front"></figure> | |
<figure class="domino__bottom"></figure> | |
<figure class="domino__left"></figure> | |
<figure class="domino__shadow"></figure> | |
</div> | |
</section> | |
</div> | |
</div> | |
<div class="attribution"> | |
Original concept by <a href="https://dribbble.com/galshir" target="_blank">Gal Shir</a> | |
</div> |
const container = document.getElementById('container'); | |
const scaleButtons = document.getElementsByClassName('settings__scale'); | |
const durationButtons = document.getElementsByClassName('settings__duration'); | |
function changeScale(scale, el) { | |
removeActive(scaleButtons); | |
el.classList.add('is-active'); | |
container.style.setProperty('--scale', scale); | |
} | |
function changeDuration(duration, el) { | |
removeActive(durationButtons); | |
el.classList.add('is-active'); | |
document.documentElement.style.setProperty('--animation-duration', duration); | |
} | |
function removeActive(elements) { | |
[].forEach.call(elements, el => el.classList.remove('is-active')); | |
} |
$bg: #24527A; | |
$container-bg: #ff4470; | |
$color-front: #e7f6ff; | |
$color-left: #9bdaff; | |
$color-top: #fff; | |
$color-bottom: #65c6ff; | |
$fallPosition: rotateY(-60deg) translate3d(-70px, 30px, -100px); | |
$btn-bg: $container-bg; | |
:root { | |
--animation-duration: .5s; | |
} | |
@import url('https://fonts.googleapis.com/css?family=Roboto:300,400'); | |
html, body { | |
height: 100%; | |
min-height: 100%; | |
} | |
body { | |
margin: 0; | |
display: flex; | |
align-items: center; | |
justify-content: center; | |
font-family: 'Roboto', sans-serif; | |
font-weight: 300; | |
background: linear-gradient(to bottom right, $bg, $bg); | |
color: #fff; | |
} | |
figure { | |
margin: 0; | |
} | |
h3 { | |
font-weight: 300; | |
} | |
.attribution { | |
position: fixed; | |
bottom: 0; | |
right: 0; | |
color: #fff; | |
font-size: 12px; | |
padding: 5px; | |
a { | |
color: $container-bg; | |
} | |
} | |
.settings { | |
margin-right: 1rem; | |
width: 100px; | |
&:before { | |
content: var(--animation-duration); | |
} | |
button { | |
display: inline-block; | |
margin-bottom: .5rem; | |
margin-right: .5rem; | |
background: #fff; | |
border: none; | |
width: 40px; | |
height: 30px; | |
font-size: .8rem; | |
color: #fff; | |
background: $btn-bg; | |
border-radius: 2px; | |
cursor: pointer; | |
outline: none; | |
&.is-active { | |
background: #fff; | |
color: $container-bg; | |
} | |
} | |
} | |
.current { | |
h3 { | |
margin-top: 0; | |
} | |
padding: 1rem; | |
background: rgba(#fff,.2); | |
&__value { | |
width: 49%; | |
display: inline-block; | |
&:after { | |
content: attr(data-value); | |
} | |
} | |
} | |
.container { | |
--scale: 1; | |
width: 350px; | |
height: 300px; | |
overflow: hidden; | |
background: $container-bg; | |
transform: scale(var(--scale)); | |
transition: transform .4s ease-in-out; | |
} | |
.stage { | |
top: -225px; | |
left: -150px; | |
position: relative; | |
transform: rotate3d(6, -3, 6.2, 81deg); | |
transform-style: preserve-3d; | |
transform-origin: 0 0; | |
animation: moveStage var(--animation-duration) linear infinite; | |
} | |
.domino { | |
transform: rotateY(0deg); | |
transform-style: preserve-3d; | |
transition: transform .2s; | |
@for $i from 1 through 10 { | |
&:nth-child(#{$i}) { | |
position: absolute; | |
left: 90px * $i; | |
} | |
} | |
&:nth-child(6) { | |
.domino__front { | |
&:after { | |
content: ''; | |
position: absolute; | |
bottom: 0; | |
left: 0; | |
width: 100%; | |
height: 47%; | |
background: rgba(#000, .07); | |
box-shadow: 0 0 30px rgba(0,0,0,.1); | |
transform: scale(1,0); | |
transform-origin: 100% 100%; | |
animation: var(--animation-duration) fallShadow linear infinite; | |
} | |
} | |
} | |
&:nth-child(7) { | |
animation: fall var(--animation-duration) linear infinite; | |
.domino__front { | |
animation: fallFrontBg var(--animation-duration) linear infinite; | |
&:after { | |
content: ''; | |
position: absolute; | |
bottom: 0; | |
left: 0; | |
width: 100%; | |
height: 35%; | |
background: rgba(#000, .07); | |
box-shadow: 0 0 30px rgba(0,0,0,.1); | |
} | |
} | |
.domino__shadow { | |
animation: shadowRotate var(--animation-duration) linear infinite; | |
} | |
} | |
&:nth-child(8), | |
&:nth-child(9), | |
&:nth-child(10) { | |
transform: $fallPosition; | |
.domino__front { | |
background: #fff; | |
&:after { | |
content: ''; | |
position: absolute; | |
bottom: 0; | |
left: 0; | |
width: 100%; | |
height: 35%; | |
background: rgba(#000, 0.07); | |
box-shadow: 0 0 30px rgba(0,0,0,.1); | |
transform: scale(1,1); | |
transform-origin: 100% 100%; | |
} | |
} | |
.domino__shadow { | |
transform: rotateY(60deg) translate3d(-25px, -25px, 0px); | |
} | |
} | |
} | |
.domino figure { | |
display: block; | |
position: absolute; | |
font-size: 90px; | |
text-align: center; | |
font-weight: bold; | |
color: white; | |
backface-visibility: hidden; | |
} | |
.domino__top, | |
.domino__bottom { | |
width: 15px; | |
height: 50px; | |
} | |
.domino__front { | |
position: relative; | |
width: 50px; | |
height: 100px; | |
left: 84px; | |
} | |
.domino__left { | |
width: 15px; | |
height: 100px; | |
top: 0; | |
} | |
.domino__shadow { | |
width: 1px; | |
height: 50px; | |
background: rgba(0, 0, 0, 0.228); | |
border-radius: 10px; | |
box-shadow: 0 0 77px 10px rgba(0, 0, 0, 0.8); | |
} | |
.domino__top { background: $color-top; } | |
.domino__front { background: $color-front; } | |
.domino__left { background: $color-left; } | |
.domino__bottom { background: $color-bottom; } | |
.domino__top { | |
transform: translate3d(125px, 25px, 25px); | |
} | |
.domino__bottom { | |
transform: rotateX(180deg) translate3d(125px, -25px, 75px); | |
} | |
.domino__front { | |
transform: rotateY(-90deg) rotateX(180deg) rotateZ(90deg) translate3d(0px,25px,30px); | |
} | |
.domino__left { | |
transform: rotateX(-90deg) translate3d(125px, 25px, 25px); | |
} | |
.domino__shadow { | |
transform: translate3d(125px, 25px, -75px); | |
} | |
@keyframes moveStage{ | |
0% { | |
transform: rotate3d(6, -3, 6.2, 81deg) translate3d(0,0,0); | |
} | |
100% { | |
transform: rotate3d(6, -3, 6.2, 81deg) translate3d(90px,0,0); | |
} | |
} | |
@keyframes fall{ | |
0% { | |
transform: rotateY(0deg) translate3d(0,0,0); | |
} | |
100% { | |
transform: $fallPosition; | |
} | |
} | |
@keyframes fallFrontBg{ | |
0% { | |
background: #e7f6ff; | |
} | |
100% { | |
background: #fff; | |
} | |
} | |
@keyframes fallShadow{ | |
0% { | |
transform: scale(1,0); | |
} | |
74% { | |
transform: scale(1,1); | |
} | |
100% { | |
transform: scale(1,1); | |
} | |
} | |
@keyframes shadowRotate{ | |
0% { | |
transform: rotateY(0deg) translate3d(125px, 25px, -75px); | |
} | |
100% { | |
transform: rotateY(60deg) translate3d(-25px, -25px, 0px); | |
} | |
} |