• 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 {

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>

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.


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


    • Author: Alex
    • Posted on: 2011/04/16
    • At: 15:08

    Freaking awesome :)

    I’ve been following you on twitter the last past months. Pretty interesting. Keep on rocking!

    • Author: Bart Burkhardt
    • Posted on: 2011/04/16
    • At: 15:43

    This is amazing, how about creating a javascript library to setup such a world, creating the css transfoms stuff and so

    • Yes, I agree. A JS library is the only way to build a complex world. If this game is really going to happen I’ll surely release the framework under open source license.

    • Author: Sivan
    • Posted on: 2011/04/16
    • At: 17:51

    This is awesome.
    Just CSS3 static City is enough cool and now its CSS 3D transforms!!

    • Author: Bilez
    • Posted on: 2011/04/17
    • At: 13:53


    • Author: Steve
    • Posted on: 2011/04/18
    • At: 10:59

    I was working on the exact same example a few months ago. While canvas is an impressive alternative to pure dom scripting, I was just curious how far this approach could be pushed.

  • Sweet!
    The first demo works well in Chromium 12 as well, the second one didn’t unfortunately. Right now we’re at a split where Mozilla is betting all their 3D money on webGL, and safari, though webkit was the first engine to implement webGL, seems to refuse to put it in the mainstream releases. Honestly it seems webGL is more useful but i’d settle for any 3D technology that gets some wider adoption.


      • Author: Ilyas Kazi
      • Posted on: 2011/07/11
      • At: 14:36

      Yes it worked on Chrome browser as well.. pretty stuff!

  • Great post.

    As you suggested, maybe not the best approach a lot of times, but it’s always really interesting to read about oft-ignored dusty corners of technology.. keep it up.

    • Author: Khang Minh
    • Posted on: 2011/04/27
    • At: 18:31

    Now we need a map…

    • Author: Ricci
    • Posted on: 2011/04/30
    • At: 23:45

    Awesome! I loe the way where web design going :)

    • Author: Guilherme Mendes
    • Posted on: 2011/05/10
    • At: 14:25

    A Minecraft Javascript version?!? :-)

  • Try using the 3d transformations everywhere, it will be the sweet.

    • Author: Luke
    • Posted on: 2011/05/22
    • At: 19:39

    Really cool stuff. I’ve been playing around with a similar thing myself recently, but wondering if something is possible (I can’t figure it out!):

    Say I made a 3d ‘box’, in the same way as your first example here. Is it possible to put the ‘viewport’ or ‘camera’ *inside* that box, so when I rotate the box, what the user sees is themselves inside the box, with the box rotating around them?

    If I translateZ the box towards the screen, the perspectiveOrigin stays in the same place, but if I move the perspectiveOrigin as well, then I can never be ‘inside’ the box, I’m always outside it but just really close up!

    Any ideas?

      • Author: boblemarin
      • Posted on: 2011/07/09
      • At: 21:22

      I’m currently working on a small JS lib that works with those techniques. There is a skybox example that achieves the effect you are describing.

      See there : http://minimal.be/lab/Sprite3D

      • thanks for sharing!

        • Author: RaphaelDDL
        • Posted on: 2011/10/21
        • At: 23:43

        Bloble, nice lib you are doing, i’ll check it out more =D

    • Author: CJ Spencer
    • Posted on: 2011/06/17
    • At: 12:53

    Brilliant work mate, looks lovely on the iPad too!

    • Author: B4sti4n
    • Posted on: 2011/07/11
    • At: 01:28

    Everything works with Chrome as well.

    • yep, since v13 I believe

  • Wow this is pretty insane! It is exciting to see this new technology, and I appreciate your tinkering. Thanks man!

  • Awesome work!
    I want to create a rubik’s cube using divs, I have the 2D version but translating it into 3d was a mystery. I have got a idea thanks to this. Will give it a try

    • Author: darwin
    • Posted on: 2011/07/11
    • At: 17:08

    cool…hope in the future all browser can support css transform

  • God! my good old 3d demo days are back in browser (#CITY)

  • Next up, SimCity in pure CSS?

    • Author: Kai
    • Posted on: 2011/07/12
    • At: 16:56

    Thats pretty awesome!!! Nice Work :)

    • Author: Kat
    • Posted on: 2011/07/12
    • At: 17:33

    Instead of saying “Safari” or “Safari and iPad/Phone” only, you should’ve just said the demos only work properly in most webkit browsers since that’s the rendering technology you’re using.

    Yes, I’m nitpicking, but it’s annoying that this many years later iFans are still going “Safari/i___ EXCLUSIVE!!!!!” and not understanding the technology behind it.

    Of course, saying “This demo working is most webkit browsers such as Safari” is perfectly true and acceptable.

    • Dear Kat,
      when this demo was released the only browser supporting 3D translation was Safari (browser and mobile). Only few weeks ago Chrome added css 3d support.

    • Author: Joe Bracken
    • Posted on: 2011/07/12
    • At: 18:32

    Wow impressive.

  • That is mind blowing!

    • Author: Andy
    • Posted on: 2011/07/12
    • At: 20:41

    Byzantine perspective.

    • Author: dude
    • Posted on: 2011/07/13
    • At: 01:32

    @kat, that I call envy!

    • Author: Dan
    • Posted on: 2011/07/13
    • At: 07:23

    So coooooooool…

  • Pure awesomeness: I’ll apply it somewhere soon!
    Thank you for the great study you did! This experiment makes my life a lot easier!

  • The first demo (modern wekbit only) doesn’t work on Chrome (current version). Just a heads up.

    I love the concept of this, great work!

    • weird, it works for me. what chrome version?

  • Google Chrome v12.0.742.122

    I only see the bottom layers of the buildings, not the buildings themselves, and no grass either.

    • operating system?

      • Windows 7 (32-bit)
        HP Compaq 8000 Elite CMT PC
        Intel Core, 2 Duo CPU – E8400 @ 3.00GHz

      • maybe mac and win versions are not exactly the same

  • Also, why isn’t there a reply button on your comment to me?

    • Author: BrianMB
    • Posted on: 2011/07/15
    • At: 17:00

    I also did something like this (and it also works properly only in Safari):

    Click the “Fourth of July” button!

  • VRML is going to make a big come back…with CSS!!!

    • Author: Ana
    • Posted on: 2011/07/20
    • At: 16:07

    This is pretty awesome. I just started looking into alternatives for game development. Definitely something i want to start with.