Skip to Content
Create a Chess Board with CSS Subgrid

Create a Chess Board with CSS Subgrid

I’m so excited about a new CSS feature that should make designing layouts much simpler. Thanks to interop 2023, CSS now has a snazzy new feature that allows you to set up child elements to a grid as a subgrid element. In this article, I’ll explain what CSS subgrid is and how to create a Chess Board with CSS Subgrid.

Want more use cases from interop? Check out our post on container queries made easy and don’t miss this one about CSS Layer use cases!

How CSS Subgrid Works

Before subgrid, setting up a design on a grid layout could become cumbersome with the need to set multiple elements to the same grid-template-columns or grid-template-rows values as a parent element. The beauty of CSS subgrid is that it allows you to pass the grid down essentially from parent to child. Additionally, you can maneuver the subgrid of the parent to be shaped differently so that its children can be positioned differently but in line with its ancestors.

Here’s a quick example of subgrid in action

Take this bare bones CSS below, in my example I’ve duplicated the “child” element 5 times giving me a total of 6 child divs.

<div class="parent">
  <div class="child">
    <div class='grandchild'></div>

I’ve started with the following CSS:

.parent {
  display: grid;
  grid-template-columns: repeat(3, 25%);
  grid-template-rows: repeat(2, 100px);
  gap: 10px;
.child {
  border: 1px solid #000;
  background-color: #80008059;

This CSS is laying out a 3X2 grid. Each child block has a background color and border. As you can see in the image below, the child elements take need no grid settings to fill up each block.

Let’s make some alterations to our grid. First I’m going to update my child selector to only style the first block. Then I’m only going to style the grandchild of that first block:

.child:nth-of-type(1) {
  border: 1px solid #000;
  background-color: #80008059;
    display: grid;
  grid: subgrid;
  grid-column: span 2;

In the above code, I’ve added the grid: subgrid; property which sets both the grid-template-columns, and grid-template-rows to the subgrid. Next, I’m setting my grid-column property to span 2 columns.

As you can see below, we end up with a block that’s now spanning 2 columns of our parent grid.

You won’t notice much difference between this behavior and if you were to remove the display grid and grid subgrid properties. But without these properties the grandchild element has no height or width.

Let’s add a background color to the grandchild element:

.child:nth-of-type(1) .grandchild {
  background-color: #ff000036;

Now notice how the grandchild element has inherited the grid styles of its parent.

If you go back and comment out the subgrid properties you’ll notice that the grandchild element is no longer visible:

Let’s Make a Chess Board!

The CSS subgrid chess board we’re about to make could be built with just grid and without subgrid, but we can use subgrid on our chess squares can use grid positioning properties like align-items and justify-items.

Skeleton HTML

To start off, the only HTML we’ll need is the following. We’re going to create elements with Javascript and add classes to them dynamically so that we can let javascript do the heavy lifting.

<div class="table">
<div class="board">

Create the Board with Vanilla JS

First let’s start by defining a couple of variables.

const board = document.querySelector('.board');
const boardSquares = document.querySelectorAll('.square')

You’ll notice that our HTML has only one element with table class, and one with board. We’re going to create div’s with the class “square” and insert them into the board.

for(i = boardSquares.length; i < 64; i++) {
  //create the div
  const createSquare = document.createElement("div");
  // add the class name square
  // insert the boardSquare
  board.insertAdjacentElement('beforeend', createSquare);

In the above code, we’re using a traditional for loop to get the length of the boardSquares variable. If it’s less than 64 (the amount of squares on a chess board), we want to create a div, add the class name “square” to it and then insert it into the board.

Style the Chess Board with CSS Subgrid

In our stylesheet let’s style the table and board like so:

.table {
  display: flex;
  justify-content: center;
.board {
  display: grid;
  grid-template-columns: repeat(8, 4em);
  grid-template-rows: repeat(8, 4em);

As you can see in the above code, we’ve defined a grid that is 8X8 and 4em of the width and height. The table styles should center the board in the middle of the page for us.

We’ll add the square classes now to center our pieces when we’re ready to insert them into the page:

.square {
  display: grid;
  grid-template-columns: subgrid;
  border: 1px solid #000;
  align-items: center;
  justify-items: center;

Notice that we’re also adding a border around each square to polish our board.

Make the black squares

Next we are going to add a class to our CSS called .black and simply style the font color and background color:

.black {
  background: #000;
  color: #fff;

Inside the loop, we’re going to create the checker board.

  // add the index as a class.
  const indexVals = [1, 3, 5, 7, 8, 10, 12, 14, 17, 19, 21, 23, 24, 26, 28, 30, 33, 35, 37, 39, 40, 42, 44, 46, 49, 51, 53, 55, 56, 58, 60, 62];
  //filter through the classes with the indexVal numbers and add the .black class
  indexVals.filter((idx) => createSquare.classList.contains(idx) ? createSquare.classList.add('black') : '');

The above code is adding the number of each element as a class name. Then we’re defining an array of the squares that will be black. Finally, if the index of the array is contained within the class names of the createSquare element we’re adding to our board, add the class “black”.

Important: Make sure that as you add code to the loop you always leave this line at the very end before the loop’s closing bracket:

  board.insertAdjacentElement('beforeend', createSquare);
//loop closing bracket

Create and Insert the Chess Pieces

First, let’s create assign each unicode chess piece to a variable:

// white chess piece unicodes
const knightW = '&#9816';
const queenW = '&#9812';
const kingW = '&#9813';
const rookW = '&#9814';
const bishopW = '&#9815';
const pawnW = '&#9817';

// black chess piece unicodes
const knightB = '&#9822';
const queenB = '&#9818';
const kingB = '&#9819';
const rookB = '&#9820';
const bishopB = '&#9821';
const pawnB = '&#9823';

Next, I created this function because I noticed while coding this that if I didn’t, I was going to end up with a lot of repeated code.

// Function to insert piece
const insertPiece = (arr, el, piece) => {
  arr.filter((idx) => el.classList.contains(idx) ? el.insertAdjacentHTML('afterbegin', `<div class='piece'>${piece}</div>`) : '');

The above function has 3 parameters:

  • arr = an array of numbers associated with each piece’s starting position
  • el = the element to insert the piece inside of
  • piece = an html tag with a class of ‘piece’ and the chess piece unicode inside of it

When we call this function we’re going to assign each of these parameters to the appropriate variable.

The arr values we’ll define inside our loop:

  const rookBVals = [0, 7];
  const rookWVals = [56, 63];
  const knightBVals = [1, 6];
  const knightWVals = [57, 62];
  const bishopBVals = [2, 5];
  const bishopWVals = [58, 61];
  const pawnBVals = [8, 9, 10, 11, 12, 13, 14, 15];
  const pawnWVals =[48, 49, 50, 51, 52, 53, 54, 55];

Next, we can call our insertPiece function for each of the arrays we’ve defined above and for each html unicode that represents a chess piece:

  insertPiece(rookBVals, createSquare, rookB);
  insertPiece(rookWVals, createSquare, rookW);
  insertPiece(knightBVals, createSquare, knightB);
  insertPiece(knightWVals, createSquare, knightW);
  insertPiece(bishopBVals, createSquare, bishopB);
  insertPiece(bishopWVals, createSquare, bishopW);
  insertPiece([3], createSquare, kingB);
  insertPiece([4], createSquare, queenB);
  insertPiece([59], createSquare, kingW);
  insertPiece([60], createSquare, queenW);
  insertPiece(pawnBVals, createSquare, pawnB);
  insertPiece(pawnWVals, createSquare, pawnW);

Be sure to place each of these function calls inside the loop as well. Note that the createSquare element is the el variable definition for all of these function calls, and the unicode of each chess piece is the piece variable.

The final piece of the puzzle is to add a style to the piece to ensure it’s large enough to look normal:

.piece {
  font-size: 2.75em;

And that’s it! We’ve made a chess board with CSS subgrid and pure code! We are using very little html, and not much CSS to achieve this feat. Subgrid is used here on our board to center our pieces on the square elements using align-items and justify-items.

See the full code here:

Photo by Hassan Pasha on Unsplash