Cubes Advent Calendar

A 3D cubes Advent calendar with fun hover effects and background color animations. Clicking the boxes opens another content level with different element animations.


View demo Download source

Today we’d like to share a fun little Advent calendar with you. The idea is mainly inspired by the Singles 2016 page of Adult Swim. When hovering over the boxes, they rotate in a fun way and when we click on a box, all boxes disappear with an animation. Then some content shows up, also animating with individual effects. Additionally, we have the option to tilt the whole calendar according to the hover position.
We’ve created some demos for your inspiration and hope that you can use this as a base for your Christmas ideas.

The animations are powered by Julian Garnier’s anime.js. We also use some text animations based on one of our previous demos, Inspiration for Letter Effects, where we employ Charming.js by Yuan Qing. The snow animation if from Om Shankar’s gist snow.html.


Please note that this is limited to browsers that support Flexbox and transform-style: preserve-3d. Although Firefox supports these, it currently does not respect the 3D depth ordering due to this bug, and/or this bug. If you’d like to learn more on the gotchas of CSS 3D, read this great article by Ana Tudor on CSS-Tricks: Things to Watch Out for When Working with CSS 3D.



For our Advent calendar we are using a Flexbox layout. The cubes are created from a “flat” structure and transformed into a multi-element structure that allows us to create the three-dimensional look. The respective content elements follow, each enclosed in a content__block:

<div class="calendar-wrap">

	<div class="calendar">
		<div class="cubes">

			<div class="cube">
				<div class="cube__side cube__side--back"></div>
				<div class="cube__side cube__side--left"></div>
				<div class="cube__side cube__side--right"></div>
				<div class="cube__side cube__side--bottom"></div>
				<div class="cube__side cube__side--top"></div>
				<div class="cube__side cube__side--front">
					<div class="cube__number">1</div>

			<div class="cube">
				<!-- ... -->
			<!-- ... -->
		</div><!-- /cubes -->

		<h2 class="title">The Title</h2>

	</div><!-- /calendar -->

	<div class="content">

		<div class="content__block">
			<h3 class="content__title">The Title</h3>
			<p class="content__description">If everyone demanded peace instead of another television set, then there'd be peace.</p>
			<p class="content__meta">John Lennon</p>

		<div class="content__block">
			<!-- ... -->

		<div class="content__number">0</div>

		<button class="btn-back" aria-label="Back to the grid view">↵</button>

	<!-- /content -->

The shared styles of all demos are defined in common.css while individual adjustments are made in style1.css, style2.css and style3.css.



Note that the initial structure has some data attributes that are used for the background color animation, the inactive class and to construct the title element that appears on hover. Have a look at the html files to see the markup.

Some interesting styles are the ones for building the cubes container and its cubes. Note that the cubes container gets created dynamically in our script. We explicitly use calc() here to show how the padding of the main calendar container is calculated. For seven boxes in a row, we subtract the width of them (counting with their margins) from the viewport width and divide it by two in order to get the padding for one side.

.calendar {
	position: relative;
	width: 100%;
	height: 100%;
	margin: 0 auto;
	overflow: hidden;
	/* we always want 7 boxes in a row */
	padding: 3em calc((100vw - (7 * (7vw + 1vw)))/2);

.js .calendar {
	position: absolute;
	perspective: 1000px;
	padding: 0 calc((100vw - (7 * (7vw + 1vw)))/2) 5em;

.no-js .calendar {
	display: flex;
	flex-wrap: wrap;
	align-content: center;
	align-items: center;

/* Cubes container */

.cubes {
	display: flex;
	flex-wrap: wrap;
	align-content: center;
	align-items: center;
	width: 100%;
	height: 100%;
	transform-style: preserve-3d;

The cube is a 3D construct that needs to have the correct transforms for the sides. We use viewport units to make our cube responsive.

/* Single cube */

.cube {
	position: relative;
	display: block;
	flex: none;
	width: 7vw;
	height: 7vw;
	margin: 0.5vw;

.js .cube {
	flex: auto;
	transform-style: preserve-3d;

/* Push to the right weekday (we have to push 3 boxes) */

.js .cube:first-child {
	margin-left: calc(((7vw + 1vw) * 3) + 0.5vw);

.js .cube:not(.cube--inactive) {
	cursor: pointer;

/* Cube sides and rotations */

.cube__side {
	position: absolute;
	top: 0;
	left: 0;
	width: inherit;
	height: inherit;
	backface-visibility: hidden;

.cube__side--front {
	position: relative;
	transform: translateZ(3.5vw);

.cube__side--back {
	transform: rotateY(180deg) translateZ(3.5vw);

.cube__side--right {
	transform: rotateY(90deg) translateZ(3.5vw);

.cube__side--left {
	transform: rotateY(-90deg) translateZ(3.5vw);

.cube__side--top {
	transform: rotateX(90deg) translateZ(3.5vw);

.cube__side--bottom {
	transform: rotateX(-90deg) translateZ(3.5vw);

Each demo has an individual script file where you’ll find all the functionality and the animations.



Browser Support:
  • ChromeSupported
  • FirefoxNot supported
  • Internet ExplorerSupported from version E
  • SafariSupported
  • OperaSupported

Update: If you need a fix for Firefox, check out xem’s solution here and here. Read more about it in this GitHub issue. Thank you, xem!

References and Credits

View demo Download source


Tagged with:

ML is a freelance web designer and developer with a passion for interaction design. She studied Cognitive Science and Computational Logic and has a weakness for the smell of freshly ground peppercorns.

View all contributions by


Related Articles

CSS Reference

Learn about all important CSS properties from the basics with our extensive and easy-to-read CSS Reference.

It doesn't matter if you are a beginner or intermediate, start leanirng CSS now.

Feedback 11

  1. 4

    Super happy with this. Was looking for a cool way to better my portfolio, gonna find a cool way to use this there. Thanks for the share. :)

  2. 8

    Fix for Firefox, add to common.css

    .cube:nth-child(0){z-index: 25}
    .cube:nth-child(1){z-index: 24}
    .cube:nth-child(2){z-index: 23}
    .cube:nth-child(3){z-index: 22}
    .cube:nth-child(4){z-index: 19}
    .cube:nth-child(5){z-index: 20}

    .cube:nth-child(6){z-index: 29}
    .cube:nth-child(7){z-index: 28}
    .cube:nth-child(8){z-index: 27}
    .cube:nth-child(9){z-index: 26}
    .cube:nth-child(10){z-index: 25}
    .cube:nth-child(11){z-index: 10}

    .cube:nth-child(12){z-index: 12}
    .cube:nth-child(13){z-index: 13}
    .cube:nth-child(14){z-index: 11}
    .cube:nth-child(15){z-index: 10}
    .cube:nth-child(16){z-index: 9}
    .cube:nth-child(17){z-index: 8}

    .cube:nth-child(18){z-index: 24}
    .cube:nth-child(19){z-index: 25}
    .cube:nth-child(20){z-index: 26}

    .cube:nth-child(21){z-index: 4}
    .cube:nth-child(22){z-index: 3}
    .cube:nth-child(23){z-index: 2}
    .cube:nth-child(24){z-index: 1}

  3. 9

    This is great. But how do you stop people clicking and activating future dates?
    I.e if its the 3rd how do you deactivae the 4th upwards

  4. 10

    Thanks for the great scripts and desing. Have an Advent calendar of holiday audio stories now running at:

    {Also added a script that only displays boxes for the current and past days so you don’t have to manually update daily.)

Follow this discussion

Leave a Comment