• Posted on: Apr 16, 2011
  • Tag:
  • Reactions: 80

> Building a pure CSS 3D City

css 3d building

I was recently experimenting with CSS 3D transforms. Is it possible to build a 3D city with just CSS? Yesterday I’ve posted on twitter about a quick CSS 3D demo, here comes the follow up blog post.

Most of you are aware that Safari and most decent modern browsers support CSS rotation. No javascript nor plugins involved.

The following code rotates #element by 15 degrees.

#element {
	-moz-transform:rotate(15deg);
	-webkit-transform:rotate(15deg);
	-o-transform:rotate(15deg);
	transform:rotate(15deg);
}

Okay, admittedly, this is boring. What is really interesting is that Safari (mobile version included) and Chrome support transforms on a 3D matrix, opening an endless range of opportunities.

I was wondering if this could be used in a real world application. How many 3d objects can you place on screen before slipping in the dreaded mobile browser crash?

My task was to build a SimCity like pure CSS block. Buildings are easy, they are just cubes with a fancy texture.

Setting up the first building

The following is what we are going to achieve:

And this is the live demo. (modern wekbit only).

Each building is composed by 5 sides (we don’t need the bottom/ground side, as it is not visible).

The HTML will look something like this:

<div class="building">
	<div class="side1"></div>
	<div class="side2"></div>
	<div class="side3"></div>
	<div class="side4"></div>
	<div class="side5"></div>
</div>

We have 5 overlapping divs, now we need to rotate and translate them to obtain a cube.

Rotating side 1 by 90deg on the Y axis (-webkit-transform:rotateY(90deg)) we get this:

An useful CSS property is -webkit-transform-origin , with it we can change the origin of the rotation. Adding -webkit-transform-origin:100% 0; we get pretty close to what we are aiming:

But if we add a texture to the face we notice that the wall is in the wrong orientation.

We need to rotate the wall onto the Z axis and translate it a bit. We finally have the right side.

The end CSS is:

-webkit-transform:rotateY(90deg) rotateZ(-90deg) translateY(-100%);
-webkit-transform-origin:100% 0;

You can obtain the same result with transforms only, it is not needed to change the object origin. That’s up to you. A webkit-transform only solution might be like so:

-webkit-transform:rotateY(90deg) rotateZ(-90deg) translate3d(0,-50%,50px);

Now repeat for all sides. Watch the end result on any Safari or Chrome.

Performance

My main concern was about performance. How is this going to scale with -say- 16 or 32 buildings? Each element needs six divs to be rendered (five sides plus one container) and from my experience with iScroll I know that the iPad doesn’t like pages with too many elements.

So I multiplied the building by 16 and surprisingly the iPad is able to serve a smooth and frame rate steady animation.

The problem here is that we need 96 divs to build 16 boxes. Not elegant at all, so I tried a different approach.

Reducing DIVs count with a different approach

Have a look at this second experiment:

We have 6 buildings but the whole city is composed by 19 divs only (not 36), and placing more buildings doesn’t require adding more divs. With the very same installation you could have 16 buildings without touching the DOM.

It’s a bit tricky, but the following picture should unveil the mystery:

The red transparent layers are the actual DIVs. I have the same number of elements on the other axis of course. I didn’t use 6 elements per building, I just have a 8×8 grid of divs.

Setting up the city is just a matter of placing the right texture (background) in the right place, and –as CSS3 supports multiple backgrounds– your city is a few CSS properties away.

Here’s how the first DIV looks like:

background:url(front1.jpg) 0 100%,
	url(front1.jpg) 100px 100%,
	url(front1.jpg) 100px 0,
	url(front2.jpg) 300px 100%,
	url(front2.jpg) 300px 0;

And here’s the live demo (Safari or iPad/iPhone only, as always).

Now the problem is that, even if composed by fewer elements, this second experiment is far slower than the 6-divs-per-building solution. Maybe Safari webkit doesn’t like crossing transparent layers, or elements with multiple backgrounds. Either way if you are going to release the next full CSS3 SimCity or GTA, you better go with the first solution pictured in this post.

Does it really matter?

Why the hell are you doing this? You may argue. After all we have canvas with which people are releasing Quake Arena clones at 60fps.

First of all some devices and older PCs perform really bad with canvas. The iPad and iPhone for example do not really like it, while 3d transforms are hardware accelerated.

Secondly, we are more accustomed to work with DOM elements than canvas madness. This doesn’t mean that we shouldn’t use canvas, I’m just offering an alternative.

Future development

This experiment gave me a fair amount of new ideas for an iPad multiplayer game. If you want to stay with me, I’ll post the project progress here on my blog and later on the game’s site if things get serious. Stay tuned.

/Share the joy

/Reactions