Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
(βŒπŸ”΄_πŸ”΅) Turnable Tables, Part 1 (πŸ”΄_πŸ”΅Β¬) | 3D CSS Record Player | @keyframers 1.18.0

(βŒπŸ”΄_πŸ”΅) Turnable Tables, Part 1 (πŸ”΄_πŸ”΅Β¬) | 3D CSS Record Player | @keyframers 1.18.0

Stephen Shaw and a faintly appearing David Khourshid create a 3D turntable with CSS! Control the rotation & open the lid with the power of CSS Variables.

Skip around: 2:00 Animation overview 6:00 Start coding 1:40:00 Keyflections

Like what we're doing? There are many ways you can support @keyframers so we can keep live coding awesome animations!

Topics covered:

  • CSS Variables
  • CSS 3D
  • input[type="range"]

A Pen by @keyframers on CodePen.

License.

<a href="https://youtu.be/tdWxCsAqx7I" target="_blank" data-keyframers-credit style="color: #000"></a>
<script src="https://codepen.io/shshaw/pen/QmZYMG.js"></script>
<div class="container">
<div class="controls">
<input id="rotateY" type="range" min="0" max="1" step="0.01" value="0" />
<input id="open" type="range" min="0" max="1" step="0.01" value="0" />
</div>
<div class="turntable">
<div class="turntable-top prism">
<div class="side top"></div>
<div class="side bottom"></div>
<div class="side left"></div>
<div class="side right"></div>
<div class="side front"></div>
<div class="side back"></div>
</div>
<div class="turntable-bottom prism">
<div class="side top">
<div class="record"></div>
<div class="needle-base">
<div class="needle"></div>
</div>
</div>
<div class="side bottom"></div>
<div class="side left"></div>
<div class="side right"></div>
<div class="side front"></div>
<div class="side back"></div>
</div>
<div class="shadow"></div>
</div>
</div>
// console.clear();
const elTurntable = document.querySelector('.turntable');
const elRotateY = document.querySelector('#rotateY');
elRotateY.addEventListener('input', e => {
elTurntable.style.setProperty('--rotateY', elRotateY.value);
});
const elOpen = document.querySelector('#open');
elOpen.addEventListener('input', e => {
elTurntable.style.setProperty('--open', elOpen.value);
});
$color-wood: #FEC288;
#rotateY {
position: absolute;
top: 0;
left: 50%;
display: block;
transform: translate(-50%, 1.75em);
z-index: 20;
}
#open {
position: absolute;
left: 100%;
transform: rotate(-90deg) translateY(.5em);
z-index: 20;
}
body {
perspective: 600px;
transform-style: preserve-3d;
}
.container {
transform-style: preserve-3d;
font-size: 20vmin;
}
.turntable {
transform-style: preserve-3d;
transform-origin: bottom center;
pointer-events: none;
}
.prism {
position: absolute;
top: 50%;
left: 50%;
margin: calc(-1 * var(--height)/2) calc(-1 * var(--width)/2);
transform-style: preserve-3d;
--width: 1em;
--height: 1em;
--depth: 1em;
width: var(--width);
height: var(--height);
}
.side {
position: absolute;
top: 50%;
left: 50%;
width: var(--width);
height: var(--height);
border: solid .1px #000;
transform-style: preserve-3d;
--rotation: rotateY(0);
--z: 1em;
transform: translate(-50%,-50%) var(--rotation) translateZ( calc( var(--z) / 2 ) );
&:before {
content: '';
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
background-color: black;
opacity: var(--shade, 0) !important;
}
}
.top,
.bottom {
background: $color-wood;
height: var(--depth);
--z: var(--height);
--shade: 0;
}
.left,
.right {
background: red;
width: var(--depth);
--z: var(--width);
--shade: 0.1;
}
.front,
.back {
background: blue;
--z: var(--depth);
--shade: 0.1;
}
.top { --rotation: rotateX(90deg); }
.bottom { --rotation: rotateX(-90deg); }
.left { --rotation: rotateY(90deg); }
.right { --rotation: rotateY(-90deg); }
.front { --rotation: rotateY(0deg); }
.back { --rotation: rotateY(180deg); }
/* ---------------------------------- */
.turntable-top {
--width: 2em;
--height: .5em;
--depth: 1.5em;
transform: translateY(-.45em);
.bottom { display: none; }
.side {
background-color: #aaa;
border-color: darken(#888,20%);
opacity: 0.5;
}
}
.turntable-bottom {
--width: 2em;
--height: .2em;
--depth: 1.5em;
> .side {
background: $color-wood;
border-color: desaturate(darken($color-wood,20%),40%);
}
}
/* ---------------------------------- */
.turntable {
--rotateY: 0;
--open: 0;
width: 1em;
height: 1em;
transform:
rotateX( calc( -20deg + (-40deg * var(--open)) ) )
rotateY( calc( -360deg * var(--rotateY) ) );
}
.turntable-top {
transform:
translateY( calc( -1 * var(--height) / 1.5 ) )
rotateX( calc( 70deg * var(--open) ) );
transform-origin: center
calc( 1 * var(--height) )
calc( -1 * var(--depth) / 2 );
}
/* ---------------------------------- */
.container {
transform:
rotateX( 5deg )
rotateY( 0deg );
animation: intro 3s cubic-bezier(.5, 0, .5, 1) backwards .5s;
@keyframes intro {
from {
transform:
rotateX( -50deg )
rotateY( -360deg );
}
}
}
.controls,
.turntable {
animation: inherit;
animation-name: none;
}
.controls {
animation-name: fade-in;
@keyframes fade-in {
0%, 80% { opacity: 0; }
}
}
.turntable-top {
animation: inherit;
animation-name: intro-top;
@keyframes intro-top {
from {
transform:
translateY( calc( -1 * var(--height) / 1.5 ) )
rotateX( 70deg );
}
}
}
/* ---------------------------------- */
.shadow {
position: absolute;
top: 30%;
left: 50%;
height: 1em;
width: 1em;
background: rgba(black, 0.2);
transform-style: preserve-3d;
transform:
translate(-50%, 0)
rotateX( calc(90deg + (var(--open) * 20deg)));
box-shadow: 0 0 .5em .5em rgba(black, 0.2);
}
/* ---------------------------------- */
.record {
position: absolute;
height: var(--depth);
width: var(--depth);
left: 0;
border-radius: 50%;
background-color: #5A5A5A;
transform: translateZ(10px) scale(0.8);
z-index: 2;
transform-style: preserve-3d;
&:before {
content: '';
height: 100%;
width: 100%;
position: absolute;
top: 0;
left: 0;
background-color: #AEACAB;
border-radius: inherit;
transform: translateZ(-5px) scale(1.05);
}
&:after {
content: '';
height: 100%;
width: 100%;
position: absolute;
top: 0;
left: 0;
border-radius: inherit;
transform: translateZ(-9.5px) scale(.5);
box-shadow: 0 0 2rem 4rem rgba(black, 0.2);
}
}
.needle-base {
position: absolute;
background-color: #75726B;
height: calc(var(--depth) / 2);
width: calc(var(--depth) / 2);
right: 10%;
top: 15%;
border-radius: 10px;
transform: translateZ(5px);
transform-style: preserve-3d;
&:before {
content: '';
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
border-radius: inherit;
background-color: #000;
transform: translateZ(-5px);
}
&:after {
content: '';
position: absolute;
height: 90%;
width: 25%;
right: 10%;
top: 0;
transform: translateZ(1px);
border-radius: 5px;
border-top-left-radius: 0;
border-top-right-radius: 0;
background-color: #fff;
}
}
/* ---------------------------------- */
*, *:before, *:after {
position: relative;
box-sizing: border-box;
//transition: all .5s cubic-bezier(.5, 0, .5, 1);
}
body {
background: #DFDeD9;
display: flex;
justify-content: center;
align-items: center;
overflow: hidden;
&:before {
position: absolute;
color: rgba(black, 0.3);
font-size: 10vmin;
top: 1vmin;
width: 100%;
text-align: center;
//content: 'πŸ‘» gotta go πŸ‘‹';
animation: spooky 3s infinite alternate both;
@keyframes spooky {
from {
opacity: 0.2;
transform: skewX(-10deg);
}
to {
opacity: 1;
transform: skewX(10deg);
}
}
}
}
html, body {
height: 100%;
width: 100%;
padding: 0;
margin: 0;
}
.side {
display: flex;
justify-content: center;
align-items: center;
&:before {
opacity: 0;
font-size: 20px;
color: white;
// content: attr(class);
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.