<div class="scene">
<div class="cube">
<div class="cube__face cube__face--front">front</div>
<div class="cube__face cube__face--back">back</div>
<div class="cube__face cube__face--right">right</div>
<div class="cube__face cube__face--left">left</div>
<div class="cube__face cube__face--top">top</div>
<div class="cube__face cube__face--bottom">bottom</div>
</div>
</div>
<p>
<label>
perspective
<input class="perspective-range" type="range" min="1" max="1000" value="400" data-units="px" />
</label>
</p>
<p>
<label>
perspective-origin x
<input class="origin-x-range" type="range" min="0" max="100" value="50" data-units="%" />
</label>
</p>
<p>
<label>
perspective-origin y
<input class="origin-y-range" type="range" min="0" max="100" value="50" data-units="%" />
</label>
</p>
<p>
<label>
Spin cube
<input class="spin-cube-checkbox" type="checkbox" />
</label>
</p>
<p>
<label>
Backface visible
<input class="backface-checkbox" type="checkbox" checked />
</label>
</p>
* { box-sizing: border-box; }
body { font-family: sans-serif; }
.scene {
width: 200px;
height: 200px;
border: 1px solid #CCC;
margin: 80px;
perspective: 400px;
}
.cube {
width: 200px;
height: 200px;
position: relative;
transform-style: preserve-3d;
transform: translateZ(-100px);
}
.cube.is-spinning {
animation: spinCube 8s infinite ease-in-out;
}
@keyframes spinCube {
0% { transform: translateZ(-100px) rotateX( 0deg) rotateY( 0deg); }
100% { transform: translateZ(-100px) rotateX(360deg) rotateY(360deg); }
}
.cube__face {
position: absolute;
width: 200px;
height: 200px;
border: 2px solid black;
line-height: 200px;
font-size: 40px;
font-weight: bold;
color: white;
text-align: center;
}
.cube__face--front { background: hsla( 0, 100%, 50%, 0.7); }
.cube__face--right { background: hsla( 60, 100%, 50%, 0.7); }
.cube__face--back { background: hsla(120, 100%, 50%, 0.7); }
.cube__face--left { background: hsla(180, 100%, 50%, 0.7); }
.cube__face--top { background: hsla(240, 100%, 50%, 0.7); }
.cube__face--bottom { background: hsla(300, 100%, 50%, 0.7); }
.cube__face--front { transform: rotateY( 0deg) translateZ(100px); }
.cube__face--right { transform: rotateY( 90deg) translateZ(100px); }
.cube__face--back { transform: rotateY(180deg) translateZ(100px); }
.cube__face--left { transform: rotateY(-90deg) translateZ(100px); }
.cube__face--top { transform: rotateX( 90deg) translateZ(100px); }
.cube__face--bottom { transform: rotateX(-90deg) translateZ(100px); }
.cube.is-backface-hidden .cube__face {
backface-visibility: hidden;
}
/* ==================== RangeDisplay ==================== */
// displays the value of a range input
// why isn't this in the HTML5 spec?
function RangeDisplay( input ) {
this.input = input;
this.output = document.createElement('span');
this.output.className = 'range-display';
this.units = this.input.getAttribute('data-units') || '';
// events
var onChange = this.update.bind( this );
this.input.addEventListener( 'change', onChange );
this.input.addEventListener( 'input', onChange );
// set initial output
this.update();
this.input.parentNode.appendChild( this.output );
}
RangeDisplay.prototype.update = function() {
this.output.textContent = this.input.value + this.units;
};
/* ==================== init ==================== */
// init RangeDisplays
var ranges = document.querySelectorAll('input[type="range"]');
for ( var i=0; i < ranges.length; i++ ) {
new RangeDisplay( ranges[i] );
}
var scene = document.querySelector('.scene');
var cube = document.querySelector('.cube');
var originX = 50;
var originY = 50;
function updatePerspectiveOrigin() {
scene.style.perspectiveOrigin = originX + '% ' + originY + '%';
}
// perspective
var perspectiveRange = document.querySelector('.perspective-range');
var perspectiveDisplay = perspectiveRange.parentNode.querySelector('.range-display');
perspectiveRange.onchange = perspectiveRange.oninput = function() {
var value = perspectiveRange.value + 'px';
// set to none at max
if ( value == '1000px' ) {
value = 'none';
perspectiveDisplay.textContent = 'none';
}
scene.style.perspective = value;
};
perspectiveRange.onchange();
// origin x
var originXRange = document.querySelector('.origin-x-range');
originXRange.onchange = originXRange.oninput = function() {
originX = originXRange.value;
updatePerspectiveOrigin();
};
originXRange.onchange();
// origin y
var originYRange = document.querySelector('.origin-y-range');
originYRange.onchange = originYRange.oninput = function() {
originY = originYRange.value;
updatePerspectiveOrigin();
};
originYRange.onchange();
// spin cube
var spinCubeCheckbox = document.querySelector('.spin-cube-checkbox');
spinCubeCheckbox.onchange = function() {
cube.classList.toggle( 'is-spinning', spinCubeCheckbox.checked );
};
spinCubeCheckbox.onchange();
// backface visibility
var backfaceCheckbox = document.querySelector('.backface-checkbox');
backfaceCheckbox.onchange = function() {
cube.classList.toggle( 'is-backface-hidden', !backfaceCheckbox.checked );
};
This Pen doesn't use any external CSS resources.
This Pen doesn't use any external JavaScript resources.