Admittedly not the most challenging task, but I found it entertaining. Generally speaking CSS is not very supportive when it comes to square based grids. To be more specific, making a responsive one which scales nicely. At the end I even decided to rather go with JS to make the rubrics squares, but I also reviewed the other option of making an equal side grid.

The problem

I wanted to create a little Sudoku PWA. This requires creating a board with 9×9 tiles, which should be preferably squares. I guess it’s okay to make it up of any kind of rectangles or maybe even circles, but I decided to take a conservative approach. As nowadays I’m all responsive, this grid should resize as the container of it is resized, but that’s not really supported in CSS (will see shortly, that it is actually possible, but has its flaws). Basically, since (almost) all height related attributes are based on the container’s height, sizing the height based on the width is tricky.

Only want to see the source code? Jump to the GitHub repository: https://github.com/seabadger-io/sudoku-grid

CSS-only solution

Not sure who came up with this originally, quite possibly there were more than one people coming to this solution independently. And the trick is, that relative sizing of padding (using percentage) is done based on the width. Yes, also the padding-top and padding-bottom. Saying padding: 5% will have equal padding around the element (which is nice anyway I think) and that equal padding is based on the container width.

To make square elements (using this trick it’s possible though to create rectangles with any arbitrary side ratio) the element’s before or after pseudo selector gets a 100% padding-bottom or padding-top. This of course only works if there is no content in the element, which is not really useful, but at least now the element’s height is nicely padded to take up 100% of the element’s width.

Since we probably want to add some content, in my case some number(s), this content has to be taken out of the flow using absolute positioning. And this is exactly why I didn’t go with this solution. Taking the content out of my actual flexbox grid causes all kind of issues (no relative sizing anymore, positioning the content becomes a nightmare), so I decided that if JS will be necessary anyway, will just use it to make the squares as well. There are numerous results on the web already, but just for the sake of completeness, here is some code how it would be implemented.

Something like this, you get the point.

Involving JS

In practice, the grid will be resized less times on all user’s devices all together, than the times I’ve resized it in the developer tools; pretty much only happens when the device goes from portrait to landscape or vice versa, and the rare occasions when the browser window gets resized. Therefore performance is not too much of a concern here. What I ended up with is an event listener on window resize, which sets up the squares (more or less squares, they are not supposed to be perfect) and also appropriate scales the font sizes.

The CSS part in this case is a simple flex based grid.

Adding borders

Not related to the problem, but might be useful. Here is how I created the borders which group the 3×3 squares, as this is expected on a Sudoku grid using some nth-child selectors on the tiles:

This adds the thicker lines for grouping, to be honest I’m not absolutely sure it couldn’t be simplified more, but I was happy with this.

The results

To check out the results, please visit the GitHub page of this post: https://seabadger-io.github.io/sudoku-grid/ I’ve also added some basic functionality, highlighting the rows and columns of the tile under the cursor. To get all the details, check out the source code in the GitHub repository: https://github.com/seabadger-io/sudoku-grid

Sudoku grid screen shot




Tagged with