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); | |
| } | |
| } |