> Building a pure CSS 3D City
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.
Very nice. I have been considering similar but with gradients or SVGs. I would love to add camera view as if a camera was moving around, zooming, turning etc. See my ‘Flight of the Venturer’ animation (see website linked) that shows the concept.
Cross-browser version here:
http://m8y.org/tmp/cubiq.org/dropbox/3dcity/index2.html
Not sure where he gets the grass from his video though, I couldn’t find it in the CSS. Soo, no idea if my mirror of it is complete.
don’t remember why I removed the grass from the demo. can I include your modifications to the demo?
Of course!
I mean, was just as trivial as adding the typical browser manufacturer extensions.
I wasn’t adding any browser-specific differences, since so far, there aren’t any.
So, just FYI, looks like the generic extensions never made it into your demo.
At some point hacks.mozilla.org decided to link to the link above.
http://hacks.mozilla.org/2011/10/css-3d-transformations-in-firefox-nightly/
(Search for CSS 3D city)
Of course, they probably linked to that version since yours was still not cross-browser.
BTW, I do believe the CSS transform stuff is now in Firefox Aurora which should be officially released around Christmas.
Thanks for the heads-up I’ve finally updated the demo.
BTW, that cross-browser version does work in Firefox, but requires:
https://hg.mozilla.org/mozilla-central/rev/730a82c21c53
So, nightly builds post 2011-09-30 .
http://m8y.org/tmp/cubiq.org/dropbox/3dcity/index.html
Oh, I just noticed there was an index.html as well as an index2.html
BTW, Moz guys said that ordering like index.html relies on is undefined in spec, and webkit does different things on different platforms. But apparently Mozilla will have ordering that is closer to what webkit does, more or less, shortly…
Hopefully I’m not putting words into their mouths there and I understood ‘em correctly.
Anyway, still awesome demos, esp index2.html !
Also check out my 3D CSS experiments, one very freely hand-made artistic one with images, animations…
The other one is a test to parse complete blocks with CSS from a CMS (websitebaker) and position them with x and y locs..
http://tezoner.vanallerlei.com/planetez/html5_3d/
http://tezoner.vanallerlei.com/content/pages/en-us/html_5_-_3d_area/3d_db_testje.php
Cheers, Tez
This is so awesome and very inspiring!
Can’t wait to start experimenting with this.
Thanks for sharing!
You should use kd tree depth sorting to handle depth-rendering artifacts.
What’s up colleagues, how is the whole thing, and what you wish for to say about this article, in my view its truly awesome designed for me.