Treehouse

Create a CSS Cube

By on  
CSS Cube

CSS cubes really showcase what CSS has become over the years, evolving from simple color and dimension directives to a language capable of creating deep, creative visuals.  Add animation and you've got something really neat.  Unfortunately each CSS cube tutorial I've read is a bit long and a mixes visual style with the cube basics, so I've decided to write a post which provides just the basic detail needed to create a CSS cube.  I'm basing my example off of an outstanding CodePen demo by Mircea Georgescu.

The HTML

The cube element, a wrapper in itself, will actually have a wrapper of its own:

<div class="wrap">
	<div class="cube">
		<div class="front">front</div>
		<div class="back">back</div>
		<div class="top">top</div>
		<div class="bottom">bottom</div>
		<div class="left">left</div>
		<div class="right">right</div>
	</div>
</div>

Each face of the cube will have its own element.  As you can imagine, we'll be CSS-ing the hell out of them to put them in the proper position.

The CSS

Let's take this one meaningful bit at a time.  The first meaningful element is the entire animation wrapper, which will provide a CSS perspective for the 3D element:

.wrap {
	perspective: 800px;
	perspective-origin: 50% 100px;
}

CSS perspective is a difficult concept to explain but MDN does a great job so I wont duplicate their explanation. To better understand perspective, I recommend modifying the perspective property to see how it effects the demo.  Next up is the cube container which will hold all of the different cube faces:

.cube {
	position: relative;
	width: 200px;
	transform-style: preserve-3d;
}

The cube will be 200 pixels wide, with relative positioning so that the absolutely positioned faces will stay within bounds.  We'll also use preserve-3d to keep the element 3D and not flat.  Before getting to any of the specific face rules, there will be a few general styles that will apply to each face:

.cube div {
	position: absolute;
	width: 200px;
	height: 200px;
}

With the position and dimensions of the faces set, we can get to creating the transformation code for individual faces:

.back {
	transform: translateZ(-100px) rotateY(180deg);
}
.right {
	transform: rotateY(-270deg) translateX(100px);
	transform-origin: top right;
}
.left {
	transform: rotateY(270deg) translateX(-100px);
	transform-origin: center left;
}
.top {
	transform: rotateX(-90deg) translateY(-100px);
	transform-origin: top center;
}
.bottom {
	transform: rotateX(90deg) translateY(100px);
	transform-origin: bottom center;
}
.front {
	transform: translateZ(100px);
}

The rotateY values rotate the faces of the to move the face show the text at the correct angled, while the translateZ setting moves the elements forward and backward within the stack.  The translateY setting may be confusing, but note that it represents raising or lowering a face to show 3D effect via the transparent panes.  Each face has its own translations settings to place them in the appropriate place, so feel free to modify those values to see why each corresponds to its face.

Horizontal Spinning of the Cube

Of course, what good is a 3D element set without animating it.  The answer:  none.  No good at all.  So here are a few steps we need to take to making our precious cube animate horizontally:

@keyframes spin {
	from { transform: rotateY(0); }
	to { transform: rotateY(360deg); }
}

.cube {
	animation: spin 5s infinite linear;
}

Probably easier than you think, yes?  The text looks correct due  to the facing rotation we implemented originally, and I've used keyframe animation in case we want to add more sexiness in the future.

Vertical Spinning of the Cube

Spinning the cube vertically should simple require changing the animation to Y axis, right?  Unfortunately not -- the panes as they are would show text backward in some cases, so we'll need to revise the rotation of a few elements:

@keyframes spin-vertical {
	from { transform: rotateX(0); }
	to { transform: rotateX(-360deg); }
}

.cube-wrap.vertical .cube {
	margin: 0 auto; /* keeps the cube centered */

	transform-origin: 0 100px;
	animation: spin-vertical 5s infinite linear;
}

.cube-wrap.vertical .top {
	transform: rotateX(-270deg) translateY(-100px);
}

.cube-wrap.vertical .back {
	transform: translateZ(-100px) rotateX(180deg);
}

.cube-wrap.vertical .bottom {
	transform: rotateX(-90deg) translateY(100px);
}

... as well as change the animation.

Flattening the Cube

To remove the 3D look of the cube, and simply display one block at a time (without other face hinting), remove the perspective and origin settings from the wrapper:

.wrap {
	/* no more perspective */
	perspective: none;
	perspective-origin: 0 0;
}

Now the only one face will display at any given time.

CSS cubes have been around for a while but I hope this article simplified their composition enough for you to attack your own.  And don't get discouraged if you run into issues creating your cube -- I did too!  I look forward to seeing what you create!

ydkjs-2.png

Recent Features

  • 9 Mind-Blowing Canvas Demos

    The <canvas> element has been a revelation for the visual experts among our ranks.  Canvas provides the means for incredible and efficient animations with the added bonus of no Flash; these developers can flash their awesome JavaScript skills instead.  Here are nine unbelievable canvas demos that...

  • CSS 3D Folding Animation

    Google Plus provides loads of inspiration for front-end developers, especially when it comes to the CSS and JavaScript wonders they create. Last year I duplicated their incredible PhotoStack effect with both MooTools and pure CSS; this time I'm going to duplicate...

Incredible Demos

  • Adding Events to Adding Events in MooTools

    Note: This post has been updated. One of my huge web peeves is when an element has click events attached to it but the element doesn't sport the "pointer" cursor. I mean how the hell is the user supposed to know they can/should click on...

  • Upload Photos to Flickr with PHP

    I have a bit of an obsession with uploading photos to different services thanks to Instagram. Instagram's iPhone app allows me to take photos and quickly filter them; once photo tinkering is complete, I can upload the photo to Instagram, Twitter, Facebook, and...

Discussion

  1. Fredrik

    Just a note, Firefox handles the cube in the same way as Chrome, if you add “px” after the numerical value, as stated here: https://developer.mozilla.org/en-US/docs/Web/CSS/perspective .
    perspective: 800px;

  2. I love how CSS evolved in the last few years. It’s been progressing faster and faster. :) I wonder where it will be in 5 years^^

  3. OssianGrr

    How much more complicated would it be to rotate the cube diagonally?

    • Changing the perspective-origin would allow you to do so!

  4. Thanks for the great tutorial! I used it for a CodePen I was working on. http://codepen.io/cliffpyles/pen/LHlqa

  5. Thanks for the tips and code, this is really useful!

  6. Awesome demo, like you say its great to see how far css has developed and progressed, exciting to see where things are going.

  7. Nice article and demo. Such a shame FF doesn’t anti-aliase as well as Chrome does, but at least it’s not as pants as Opera and IE10 which still aren’t on-board with any of this :-(

  8. Jeff Tackett

    Did you know that if you add a transparent outer box-shadow of 2px or more, then Firefox will render anti-aliased.
    box-shadow: 0px 0px 30px rgba(125, 125, 125, 0.8) inset, 0 0 4px rgba(0, 0, 0, 0);

  9. Hey, look my plugin for automatize this work :)
    http://github.com/ivanbanov/polygonJS

  10. Ron

    “The rotateY values rotate the faces of the to move the face show the text at the correct angled” that text doesn’t read very well.

  11. This is amazing!

    Any ideas on how to get it to work on IE 10 ?

  12. Roshdy

    Very nice tutorial.
    I’m just struggling with making the cube in % instead of px
    Can it be done?

  13. Thanks – very useful.
    Doesn’t seem to work correctly on Chrome 31 though.

  14. Interesting post! Unfortunately your Demo link goes to the Firefox animation (fire tail). At least this was true on Feb 10, 2014. Would love to see the Demo to determine if I should read the article in more detail. Thanks…

  15. Francis Underwood

    Would it be possible to make the cube smaller? I have been unable to make everything line up when I try. This is an awesome demo by the way! Thanks for sharing!

  16. Unknown

    Hi, how to build a “block” shape?
    I mean the height and the width is different

  17. Great tip. This is, what i wnat Thank you David ;)

  18. Check out my 3d cube with rotating sides, it uses mouse and touch events to allow you to move it, while keeping the content of each side rotated the right way.

    http://jordizle.com/demo/376/3d-interactive-cube-with-rotating-sides-using-css3-and-javascript/

  19. Rafael

    I have a cube with various rotations, and want to have a more realistic shadow (actually, an ellipse). So I made this code to emulate it, based on your code:

    http://jsfiddle.net/ktuw2rbr/

    Is made for Chrome only (later I will modify it). The rotation is infinite, and I want to avoid the last anticlokwise jump of my shadow.

    Any idea about to solve this problem?

Wrap your code in <pre class="{language}"></pre> tags, link to a GitHub gist, JSFiddle fiddle, or CodePen pen to embed!