The Plan
This is an evolution of an idea. At first, I wanted to see if it would be possible to use grid-areas to set up a minimalist chessboard (both positioning and movement), and it was. Then, I got into reading Eric Elliott's Composing Software, and I really wanted to toy with the idea of functionally composed elements, so the pieces on the board happened. Then I had a conversation on The Odin Project about defining interfaces for factory functions, and the Gameboard as a whole became a factory using the pieces' interface methods. It didn't happen all at once, and I won't write about it all at once.
But if you'd like to see this thing as it stands at this point in its evolution, take a look at the repl.
I plan on a three- or four-part series, depending. This one explains the theory behind the board. The next should cover the Piece factory, which covers the generic methods all pieces share. The third will explain some of how the moves are handled for each piece, exploring composed functions along the way, and finally getting into how the whole thing plays together.
I do hope you enjoy the ride!
The what
Often, when we are going through online curricula, there is a project involving building a game. Might be tic-tac-toe, might be chess, might be Battleship, but a game design happens. In this case, we'll build a chessboard.
Being fearless devs, we dive into coding, building an HTML mockup and figuring our CSS, and let's see what it might look like:
<body>
<main class='gameboard'>
<div class='cell'></div>
<div class='cell'></div>
<!-- and repeat that to make an eight-by-eight... -->
</main>
</body>
html
And the css:
.gameboard {
width: 80vw;
height: 80vw;
display: flex;
flex-wrap: wrap;
}
.cell {
width: 12.5%;
height: 12.5%;
box-sizing: border-box;
border: 1px solid silver;
}
But at that point, we have to think about this: the cells have to alternate color. We could use a css rule, something like :nth-of-child()
with some funky css magic to color alternating squares, but we have an easier solution: we can simply make the board image a background on the .gameboard
, and make those cells the same size as our image cells!
At this point, I had to stop. We could do this. This works, and it's the most common way. Make all the cells contained within the board, and set the pieces on the particular cell div as needed. Works fine.
But I don't particularly like it. It's not the way a chessboard works.
The why
Let's imagine we just went to the game store, bought a new chess set. When we open it, do we have a board, 32 chess pieces, and 64 cells? No, we do not. We have a board, and we have the pieces.
So why do we feel we need to code those cells?
We might see it as reasonable to have the cells to handle the click in a particular one, but most of us will likely use event delegation, so the clicks are happening on the board, not the cell.
Perhaps we see it as reasonable to have the cells there, in order to appropriately position the chess pieces. And this, right here, is why I want to write this article.
The how
CSS3 gave us a great many power-tools, and we don't always use them to their fullest. But this article is about using one of them in ways that can simplify things like, for example, gameboard development.
I'm talking about grids. And in particular, about the grid-area
css rule. Consider this HTML:
<div class="chessboard">
<div class="chess-piece rook black queens"></div>
<div class="chess-piece knight black queens"></div>
<div class="chess-piece bishop black queens"></div>
<div class="chess-piece queen black" ></div>
<div class="chess-piece king black"></div>
<div class="chess-piece bishop black kings"></div>
<div class="chess-piece knight black kings"></div>
<div class="chess-piece rook black kings"></div>
<div class="chess-piece rook white queens"></div>
<div class="chess-piece knight white queens"></div>
<div class="chess-piece bishop white queens"></div>
<div class="chess-piece queen white"></div>
<div class="chess-piece king white"></div>
<div class="chess-piece bishop white kings"></div>
<div class="chess-piece knight white kings"></div>
<div class="chess-piece rook white kings"></div>
</div>
And that's it. It contains everything we need to make a playable chessboard (leaving off the pawns for brevity, but the idea remains). We have a board, which contains the pieces. The pieces have class names that are pretty descriptive, we know which one's the "black queen's rook" at a glance.
Now, for the board's CSS:
.chessboard {
width: 80vmin;
height: 80vmin;
background-image: url('./quad-grid.svg');
background-position: 0 0;
background-size: 25%;
background-repeat: repeat;
/* This is the bit to watch! */
display: grid;
grid-template-columns: repeat(8, 12.5%);
grid-template-rows: repeat(8, 12.5%);
gap: 0px 0px;
grid-template-areas:
"A1 B1 C1 D1 E1 F1 G1 H1"
"A2 B2 C2 D2 E2 F2 G2 H2"
"A3 B3 C3 D3 E3 F3 G3 H3"
"A4 B4 C4 D4 E4 F4 G4 H4"
"A5 B5 C5 D5 E5 F5 G5 H5"
"A6 B6 C6 D6 E6 F6 G6 H6"
"A7 B7 C7 D7 E7 F7 G7 H7"
"A8 B8 C8 D8 E8 F8 G8 H8"
;
}
So this sizes the board, places the background image in which gives us the actual board appearance, and sets up the css grid. The grid is set up with named grid-template-areas
, named using chess notation.
And the fun part? The pieces are placed using that same chess notation!
/****
* There is some sizing and styling of the pieces,
* but this is mostly about positioning.
****/
/* Black pieces */
.black.queens.rook {
grid-area: A8;
}
.black.queens.knight {
grid-area: B8;
}
.black.queens.bishop {
grid-area: C8;
}
.black.queen {
grid-area: D8;
}
.black.king {
grid-area: E8;
}
.black.kings.bishop {
grid-area: F8;
}
.black.kings.knight {
grid-area: G8;
}
.black.kings.rook {
grid-area: H8;
}
/* White side pieces */
.white.queens.rook {
grid-area: A1;
}
.white.queens.knight {
grid-area: B1;
}
.white.queens.bishop {
grid-area: C1;
}
.white.queen {
grid-area: D1;
}
.white.king {
grid-area: E1;
}
.white.kings.bishop {
grid-area: F1;
}
.white.kings.knight {
grid-area: G1;
}
.white.kings.rook {
grid-area: H1;
}
So each piece is positioned on the board by an initial grid-area
. And further, we can later do this:
document.querySelector(".white.kings.knight").style.gridArea="F2";
And that moves the piece on the board. No worrying about calculating offsets or moving the piece, simply tell it, by css, where to move.
Top comments (11)
Why didn't you name the areas A1 to H8 - that way it becomes exactly like chess and makes it even easier to implement moves according to normal chess rules (B2 to B4) etc.
Anyway that is only a minor point, this is a great way to do it using grid! ❤
Done and done. Easier change than I'd expected - update the CSS
grid-template-areas
, then update the class to calculate the clicked grid-area (usingMath.ceil()
rather thanMath.floor()
), and working fine.Thank you again!
I had actually realized this yesterday, I'm working on this very thing. It's a great point, and thanks to the flexibility of grid-template-area, easily implemented.
Thanks for the feedback!
I guess this also has support for CSS animations perhaps?
I was working on that, and not as easy as I'd first thought. I can't figure if transitions are available from one grid-area to another, as that's not necessarily a numeric (quantitative) transform. But I might find a workaround, if I do I'll mention it here.
I had the same thought and see no reason it wouldn’t be able to achieve pretty cool animations with very little overhead.
So I had put this aside for a long while, moved on to other ideas and projects, but recently working through the logic of the Knight's Travels problems, and the fact that this was still in issue bugged the crap out of me. So I did a little digging, and found github.com/aholachek/animate-css-grid - which very cleanly, easily handles the animation between grid-areas!
The nice thing about it is, I can remove the static CSS initial values, and it was a seamless, modular update. The replit is using the animation, check it out!
Cool
Glad you like it! The fun bit comes with the javascript, to my mind. Though when I get there, I find I'm already rethinking some of the Piece factory functionality. Never satisfied, me.
Very clearly thought out. Love the design.
It was an evolution, like I said. I first just wanted to see if the grid thing works. Then Eric Elliot's book really got me thinking and wanting to do more with functional, composed objects, and it grew from there.
It is still in a state of flux, I can see a few improvements I'd like to make - I'll likely continue this series with those improvements. :D