In your post it seems you're planning on using the child <div>
elements themselves to represent the vertical and horizontal lines instead of using them to represent the grid-cell space between the lines. This is not a good approach because in CSS every element represents a 2D rectangular box, not a line (there are exceptions), and also means you lose the advantages and features provided by CSS's built-in border
and layout features (e.g. with your approach you couldn't set a cell background that's aligned with their lines/borders).
Quick solution: SVG background image
You could use a single <div>
element with an SVG background-image
:
/*
The `data:` URI is this SVG:
<svg viewBox="0 0 300 300" xmlns="http://www.w3.org/2000/svg">
<line style="stroke: rgb(0, 0, 0);" x1="100" y1="0" x2="100" y2="300"></line>
<line style="stroke: rgb(0, 0, 0);" x1="200" y1="0" x2="200" y2="300"></line>
<line style="stroke: rgb(0, 0, 0);" x1="0" y1="100" x2="300" y2="100"></line>
<line style="stroke: rgb(0, 0, 0);" x1="0" y1="200" x2="300" y2="200"></line>
</svg>
*/
.ticTacToe {
background-image: url("data:image/svg+xml;charset=utf-8;base64,PHN2ZyB2aWV3Qm94PSIwIDAgMzAwIDMwMCIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj4NCiAgPGxpbmUgc3R5bGU9InN0cm9rZTogcmdiKDAsIDAsIDApOyIgeDE9IjEwMCIgeTE9IjAiIHgyPSIxMDAiIHkyPSIzMDAiPjwvbGluZT4NCiAgPGxpbmUgc3R5bGU9InN0cm9rZTogcmdiKDAsIDAsIDApOyIgeDE9IjIwMCIgeTE9IjAiIHgyPSIyMDAiIHkyPSIzMDAiPjwvbGluZT4NCiAgPGxpbmUgc3R5bGU9InN0cm9rZTogcmdiKDAsIDAsIDApOyIgeDE9IjAiIHkxPSIxMDAiIHgyPSIzMDAiIHkyPSIxMDAiPjwvbGluZT4NCiAgPGxpbmUgc3R5bGU9InN0cm9rZTogcmdiKDAsIDAsIDApOyIgeDE9IjAiIHkxPSIyMDAiIHgyPSIzMDAiIHkyPSIyMDAiPjwvbGluZT4NCjwvc3ZnPg==");
background-size: cover;
aspect-ratio: 1/1;
/* These properties enable the draggable resize handle for "responsive" demonstration purposes: */
resize: horizontal;
overflow: hidden;
width: 300px;
}
<div class="ticTacToe"></div>
General solution: Enter display: grid;
Part 1:
- It sounds like you want a 3x3 grid where the grid cells are strictly square - that's exactly the kind of thing CSS
display: grid;
is for.
- You can also use the (relatively new)
aspect-ratio:
property to ensure the grid is always rendered as a square.
- The use of only
1fr
for the grid track size specifiers means that the cells will also be square.
- Note that as
display: grid;
gives the container block-level sizing (i.e. like <p>
or <section>
it will fill the width of its own container (so width
is computed first, and then the computed height
is derived from the computed width
(and not the other way around).
- This example below gives the cells their own borders, hence the double-border effect. (Part 2 with single-line borders is below).
.grid3x3 {
display: grid;
grid-template-columns: 1fr 1fr 1fr;
grid-template-rows: 1fr 1fr 1fr;
aspect-ratio: 1 / 1;
border: 1px outset #999;
}
.grid3x3 > div {
border: 1px inset #999;
margin: 1px;
display: flex;
align-items: center;
justify-content: center;
}
<div class="grid3x3">
<div>top-left</div>
<div>top-middle</div>
<div>top-right</div>
<div>middle-left</div>
<div>center</div>
<div>middle-right</div>
<div>bottom-left</div>
<div>bottom-middle</div>
<div>bottom-right</div>
</div>
This is how it appears in my browser at different viewport sizes:
smol:

big:

Part 2: Tic-Tac-Toe borders
The grid above resembles a <table>
more than a tic-tac-toe grid as all of the cells have their own separate inner borders, and the container has borders too.
However if you remove the borders (and the cell margin: 1px;
) and then only define vertical borders on the horizontally-centered cells, and only define horizontal borders on the vertically-centered cells, then it will look like a tic-tac-toe grid, as below:
.grid3x3 {
display: grid;
grid-template-columns: 1fr 1fr 1fr;
grid-template-rows: 1fr 1fr 1fr;
aspect-ratio: 1 / 1;
}
.grid3x3 > div {
display: flex;
align-items: center;
justify-content: center;
}
.grid3x3 > div:nth-child(2),
.grid3x3 > div:nth-child(5),
.grid3x3 > div:nth-child(8) {
border-left: 1px solid black;
border-right: 1px solid black;
}
.grid3x3 > div:nth-child(4),
.grid3x3 > div:nth-child(5),
.grid3x3 > div:nth-child(6) {
border-top: 1px solid black;
border-bottom: 1px solid black;
}
<div class="grid3x3">
<div>top-left</div>
<div>top-middle</div>
<div>top-right</div>
<div>middle-left</div>
<div>center</div>
<div>middle-right</div>
<div>bottom-left</div>
<div>bottom-middle</div>
<div>bottom-right</div>
</div>