Imagine doing the other sides of the cubes. Now orthogonal layers will be intersecting. There's no correct order in which to draw intersecting polygons. You either need to split them (and then you're back to where you started), or you need Z-buffering.
You _can_ actually do this with just one quad per plane (or maybe 2 quads - one for the front face and one for the back face)... although you're right that you can't do it using CSS (yet).
A few years back, I wrote a tech-demo^W game for Ludum Dare (http://ludumdare.com/) based on using GLSL shaders to ray cast within a cube containing voxels. I then used these cubes as 3D "sprites" for the game.
See http://matt-williams.github.io/ld29/ for the game and http://ludumdare.com/compo/2014/04/28/voxel-map-algorithm/ for a write-up of the technology.
Imagine using a stack of divs like this: https://hcgilje.files.wordpress.com/2011/01/stack.png
If each of those stacked divs represents the faces of all the 16x16 cubes in that plane, then you'd only need 48 draw calls in total. The hard part would be baking the cube textures in to a giant 'megatexture' the first place, but that could be prerendered if you didn't need animation. You'd actually need 96 images because each 'layer' would need 2 sides, but I don't see why it wouldn't work.