DEV Community

Cover image for Creating dice using CSS grid 🎲
Edwin
Edwin

Posted on

Creating dice using CSS grid 🎲

Recently, I felt like creating a game as a nice little side project. The game involves dice, so I needed some way to visualise them. This article will explain how you can create dice using only HTML and CSS.

Flexing with CSS 💪

Why reinvent the wheel if other people have already solved the problem for us, right? A quick search around the web led me to this article by Landon Schropp, which describes how to make great looking dice using CSS flexbox.

He implemented the face of a die by simply positioning a span element for each pip of the die inside of a div. The div.column contains the vertically aligned pips.



<div class="fourth-face">
  <div class="column">
    <span class="pip"></span>
    <span class="pip"></span>
  </div>
  <div class="column">
    <span class="pip"></span>
    <span class="pip"></span>
  </div>
</div>


Enter fullscreen mode Exit fullscreen mode

These pips are positioned using flexbox and pushed to opposite sides of the die using the justify-content: space-between property. His final solution requires quite a bit of CSS to correctly style every possible face value.

We can do better with CSS grid 🔥

While I was playing around with the code, I realised that the pips of a traditional die are aligned in three rows and three columns, which is a great opportunity to use CSS grid.

Imagine the face of a die as a 3x3 grid, where each cell represents the position of a pip:



+---+---+---+
| a | b | c |
+---+---+---+
| d | e | f |
+---+---+---+
| g | h | i |
+---+---+---+


Enter fullscreen mode Exit fullscreen mode

CSS grid is supported by all evergreen browsers, but as you may expect, Internet Explorer offers only very basic support. The final result will therefore not work in IE11.
For a full guide on CSS grid, please refer to the amazing Grid by Example, by Rachel Andrews.

Creating the grid layout

To create a simple 3 by 3 grid using CSS, the only thing we need to do is set a container element to display: grid and tell it that we want three equally sized rows and columns:



.face {
    display: grid;
    grid-template-rows: 1fr 1fr 1fr;
    grid-template-columns: 1fr 1fr 1fr;
}


Enter fullscreen mode Exit fullscreen mode

The fr unit allows you to set the size of a row or column as a fraction of the free space of the grid container; in our case we want one third of the available space, so we use 1fr three times.

Instead of writing 1fr 1fr 1fr we can use repeat(3, 1fr) to repeat the 1fr unit three times. We also use the grid-template shorthand property that defines rows / columns:



.face {
    display: grid;
    grid-template: repeat(3, 1fr) / repeat(3, 1fr);
}


Enter fullscreen mode Exit fullscreen mode

The only HTML that we need is a div.face container with the above CSS and a span.pip for each pip:



<div class="face">
    <span class="pip"></span>
    <span class="pip"></span>
    <span class="pip"></span>
    <span class="pip"></span>
</div>


Enter fullscreen mode Exit fullscreen mode

The pips will be automatically placed in each of the cells, from left to right:
Alt Text

Positioning the pips

Now we get to the point where we need to position the pips for each of the dice values. It would be nice if the spans automatically flowed to the correct positions in the grid for each value. Sadly, we will need to set the position of each of the pips individually.

Recall the ASCII table at the beginning of the article? We are going to create something very similar using CSS. Instead of labeling the cells in the row order, we use this specific order so we only need a minimal amount of CSS to fix the edge cases:



+---+---+---+
| a |   | c |
+---+---+---+
| e | g | f |
+---+---+---+
| d |   | b |
+---+---+---+


Enter fullscreen mode Exit fullscreen mode

Two of the cells are left empty, because they are never used on our dice.

Grid template areas

We can translate this layout to CSS using the magical grid-template-areas property (which replaces the grid-template used above):



.face {
    display: grid;
    grid-template-areas:
        "a . c"
        "e g f"
        "d . b";
}


Enter fullscreen mode Exit fullscreen mode

So instead of using traditional units to size our rows and columns, we can just refer to each cell with a name. The syntax itself provides a visualization of the structure of the grid, just like our ASCII table. The names are defined by the grid-area property of the grid item. The period in the middle column signifies an empty cell.

Placing pips in an area

We use the grid-area property to give a name to this grid item. The grid template (above) can then reference the item by its name to place it in a specific area in the grid. The :nth-child() pseudo selector allows us to target each pip individually:



.pip:nth-child(2) {
    grid-area: b;
}
.pip:nth-child(3) {
    grid-area: c;
}
.pip:nth-child(4) {
    grid-area: d;
}
.pip:nth-child(5) {
    grid-area: e;
}
.pip:nth-child(6) {
    grid-area: f;
}


Enter fullscreen mode Exit fullscreen mode

We are getting pretty close!
Alt Text

As you can see, the values 1, 3 and 5 are still incorrect. Because of the order of the grid-template-areas that we chose earlier, we only need to reposition the last pip of each of these dice. To get the result that we want, we combine the :nth-child(odd) and :last-child pseudo selectors:



.pip:nth-child(odd):last-child {
    grid-area: g;
}


Enter fullscreen mode Exit fullscreen mode

And we have our final result!
Alt Text

Setting the position of each element individually does not scale well. But for our goal, the number of cases is very limited, it works for all dice values and it allows us to keep our HTML simple. It feels like a cleaner solution than the flexbox version above. It is also easier to translate into components using a JavaScript framework such as React as you will see below.

Final result 🎲

The implementation above only uses HTML and CSS, but I also created a very basic React app to show how you can use the dice as components.

Top comments (10)

Collapse
 
maelingcodes profile image
Maeling (she/her)

This was incredibly helpful. CSS grid really does simplify the process. Thanks!

Collapse
 
maiquitome profile image
Dev Maiqui 🇧🇷 • Edited

There is a big difference in padding:

Image description

Image description

Is there an easy way to fix this?

I managed to put a dot in the middle and make it transparent, but I think it's bad code.

Image description

Collapse
 
ekeijl profile image
Edwin

This seems to work! 🎉

    grid-template-rows: repeat(3, 1fr);
    grid-template-columns: repeat(3, 1fr);
Enter fullscreen mode Exit fullscreen mode
Collapse
 
maiquitome profile image
Dev Maiqui 🇧🇷

great!!! thank you so much!!! 🙂🎉

Collapse
 
ahmedsaed profile image
Ahmed Saed

Thanks a lot

Collapse
 
ananfito profile image
Anthony Nanfito

Thank you for this post! I found it incredibly helpful on a recent project. 😃

Collapse
 
phpfui profile image
Bruce Wells

This looks great, probably the simplest CSS dice out there, but do you have a CodePen or other example? I can't seem to get it to work.

Thanks!

Collapse
 
phpfui profile image
Bruce Wells

I see the problem. I thought the last example was also an image, but it is the sandbox with the rest of the css. Thanks again, it works great!

Collapse
 
jeltzcode profile image
JeltzCode

This was a perfect find, it was easy to follow, and I learned a lot about :nth-child and :last-child in a way that made sense to me.
I found it perfect for a dice game I was making.
Thanks!

Collapse
 
ekeijl profile image
Edwin

Happy to help! :)