I experimented with using CSS Grid to create an isometric layout in this CodePen:

Here I'll explain how I made the isometric grid. If you are new to CSS Grid I would strongly recommend first checking out these resources from Rachel Andrew and Jen Simmons.

The grid is made up of three CSS Grids placed on top of each other, one for each "plane". The important thing is to make them consistently sized and aligned.

Let's create the first grid. We'll make a 10 column grid using vw units to ensure it fills the width of the screen and to allow us to size the row height the same as the column width:

  <div id="grid1" class="grid"></div>

  .grid{
  display:grid;
  width: 100vw;
  grid-template-columns: repeat(auto-fill, 10vw);
  grid-auto-rows: 10vw;
}

Now, in order to actually see our grid I will fill it with 100 cells and give these cells a border. We will get rid of these later but for now they will be useful in showing us the outline of our grid. I'll also add a number to each cell so that we can keep track of the positioning.

We now skew the grid by 30 degrees to give us one of our isometric planes.

  grid1 {
  position: absolute;
  transform-origin: 0 0;
  transform: skewY(-30deg);
}

When we do this the slanting top of each cell becomes stretched and is no longer the same size as the side of the cell. A bit of trigonometry calculates that the length has increased to 115.47% of its initial length. As we want the slanting top of the cell to be the same length as the side we need to reset our grid row height accordingly: grid-auto-rows: 11.547vw;

We now have our first grid correctly aligned.

Creating the second grid we do the same but this time we set the transform-origin to the top right and the skew to 30 degrees in the other direction.

  grid2 {
  position: absolute;
  transform-origin: 100% 0;
  transform: skewY(30deg);
}

Finally we create a third grid. This time we will skew it in the same direction as the second grid and then rotate the whole grid by 60 degrees.

  grid3 {
  position: absolute;
  transform-origin: 0 0;
  transform: rotatez(-60deg) skewY(30deg);
}

As you can see, the grid aligns correctly but the majority of the cells are beyond the edge of the screen. You can scroll right to see more of the cells.

We can also see that as we add more rows to the first two grids they will stack nicely at the bottom of the page, still within the left and right boundaries of the page. However as we add more rows to the 3rd grid we will build the grid further out to the right and no more cells will appear within the initial screen view.

To handle this and ensure we have cells in the third grid at the bottom of our page we need to make the third grid much larger than we need and accept that most of the cells will be off the edge of the screen. In effect the "height" of the third grid (how far it extends down the page) is governed by the length of the diagonal, i.e. is affected by the number of rows AND columns.

The pattern for defining this is as follows:

  grid3 {
  position: absolute;
  width: 600vw;
  transform-origin: 500vw 0;
  transform: translatex(-500vw) rotatez(-60deg) skewY(30deg);
}

We set the width to be several multiples of the screen width, allowing several more columns to be created: width: 600vw; We then translate this grid so that the new columns are positioned to the left of the screen: translatex(-500vw) We then ensure our rotation occurs around the top left of the screen, not the top left of the grid: transform-origin: 500vw 0

I've added more cells to our grid to demonstrate how they now appear.

This is certainly a messy approach and it makes it hard to work out which row and column each cell is in. When it comes to populating the grid I had to resort to a trial and error approach to place content in the correct cell. However once you have placed one cell it is possible to work out the relative position of other cells and change the row/column position accordingly.

Now that we have our grid set up I will delete our existing cells and place a few content cells instead. We will do this by specifying the grid-column and grid-row values for each cell.

And that's pretty much it. To stop the user being able to scroll to the right I wrap the three grids in a "holder" div, give it a width (100vw) and a height and set overflow:hidden.

  • Create larger panels by setting the cells to span several rows or columns.

  • Overlap cells. When overlapping cells in different grids it will be the order of the grids that determines which cell will appear on top, not the z-index within the grid. It is not possible (I don't think) to have some items from Grid 1 above items in Grid 2 with others appearing below items in Grid 2.

  • Set the grids to have smaller rows and columns to allow more variation in placement and span multiple rows/columns with each content piece.

Here's a simple example using a background image behind all 3 grids.