1

I am trying to have a div that is a square, which is the easy part, and then have tic tac toes lines inside that are equi-distant as the container grows/shrinks.

I was thinking the following setup:

<div class="container">
    <div class="vertical">
    <div class="vertical">
    <div class="horizontal">
    <div class="horizontal">
</div>

but this wouldn't allow them to take the container into account. Any ideas?

sal3jfc
  • 517
  • 4
  • 14
  • Don't. Just don't. Create your cells (Using CSS grid, or CSS flex, or with HTML table, etc) and style those instead. Don't create unnecessary elements just for the sake of having some absolute positioned stylistic-purpose-only "lines". – Roko C. Buljan Feb 20 '22 at 14:33

3 Answers3

1

Yes I have but there would be elements too for tic and toe. So you should also specify them. Then we can work for responsiveness. You can instead of that use table elements. Like This:

table{
  max-width: auto;
  width: 100%;
  min-width: 2rem;
  border: solid black;
  
}
th, td{
  white-space: wrap;
  overflow: hidden;
  height: 4rem;
}

td,th  {
  white-space: wrap;
  text-overflow: ellipsis;
  border: solid black;
  padding: 0.1rem;
  text-align: center;
  max-width: 3rem;
  min-width:0rem;

  cursor: pointer;
}

tr:hover  {
  background-color: silver;
}

img  {
  width: 100%;
  height: 100%;
}
<table>

  <tr>
    <td></td>
    <td></td>
    <td></td> 
  </tr>
  <tr>
    <td></td>
    <td></td>
    <td></td> 
  </tr>
  <tr>
    <td></td>
    <td></td>
    <td></td> 
  </tr>
</table>
ash
  • 1,065
  • 1
  • 5
  • 20
  • it's just the tic tac toe board without the actual '`x` and `o` elements. Those aren't needed. I just need the "frame" of the board. I just used "tic tac toe" to describe it because that's what it should look like – sal3jfc Feb 19 '22 at 13:28
  • is that they are fine or something else – ash Feb 19 '22 at 13:30
1

flex is appropriate for it:

* {
  box-sizing: border-box;
}

.container {
  width: 300px;
  height: 300px;
  display: flex;
  flex-wrap: wrap;
  border: solid black;
}

.container > div {
  text-align: center;
  width: calc(100% / 3);
  background-color: green;
  border: solid red 1px;
}
<div class="container">
  <div></div>
  <div></div>
  <div></div>
  <div></div>
  <div></div>
  <div></div>
  <div></div>
  <div></div>
  <div></div>
</div>
Arman Ebrahimi
  • 2,035
  • 2
  • 7
  • 20
  • 1
    I recommend you change the last selector to `.container > *` or `.container > div` to prevent inadvertent styling of unrelated descendant `div` elements. – Dai Feb 19 '22 at 13:41
  • this is only 1 vertical line and 1 horizontal line though. A tic tac toe box has 2 of each and keeping those equi-distant while resizing the container is the challenge I am having – sal3jfc Feb 19 '22 at 13:43
  • @Dai Yes, you're right. I did edit now. – Arman Ebrahimi Feb 19 '22 at 13:47
  • @sal3jfc It is easy. I did edit now. – Arman Ebrahimi Feb 19 '22 at 13:50
  • 1
    This approach doesn't work well when the `.container` doesn't have a fixed size though (e.g. set `width: 100%;` and see what happens). – Dai Feb 19 '22 at 13:55
  • @Dai Yes. but since the goal is a square, always `width` and `height` are equal. If `width` to be `100%`, and also `height` to be same of size, it works. is right? but how do we say `height` always to be equal with `width`? – Arman Ebrahimi Feb 19 '22 at 14:05
  • @ArmanEbrahimi You can't set `height: 100%;` as [percentage heights in CSS are counterintuitive](https://stackoverflow.com/questions/5657964/css-why-doesn-t-percentage-height-work). Whereas in my answer using `grid` I document how to use `aspect-ratio`. – Dai Feb 19 '22 at 14:07
  • @ArmanEbrahimi BTW, you should use `flex-basis: 33%`, not `width: calc()` for flex-items: https://stackoverflow.com/questions/34352140/what-are-the-differences-between-flex-basis-and-width – Dai Feb 19 '22 at 14:08
  • @Dai why `width: calc()` is bad? not is this more accurate than `flex-basis` when we have e.g 3 items or 6 items? because the accurate calculation of percentage is difficult. – Arman Ebrahimi Feb 19 '22 at 14:20
  • 1
    It's not about accuracy (you are right in that `calc( 100% / 3 )` is better than `33%`), but I meant the `flex-basis` property should be used instead of `width` for the reasons outlined in the linked post. – Dai Feb 19 '22 at 14:24
  • designers-aware-wise. This is all but not a tic-tac-toe styled grid. But yeah, proves that flex is great in many cases like this scenario. – Roko C. Buljan Feb 20 '22 at 14:34
1

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:

enter image description here

big:

enter image description here


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>
Dai
  • 141,631
  • 28
  • 261
  • 374
  • Excellent:) grid is very Practical. – Arman Ebrahimi Feb 19 '22 at 13:56
  • 1
    @ArmanEbrahimi `grid` does far more than just fixed grid layouts (where you manually define `grid-template-columns` and `grid-template-rows`): it also supports automatically/implicitly created rows and columns based on both the available size of the viewport (or its container) _and_ its content, which enables "responsive" (I hate that word...) layouts that support every kind of screen-size and aspect-ratio imaginable with ideal layouts without the need for manually-defined `@media` viewport queries: https://css-tricks.com/look-ma-no-media-queries-responsive-layouts-using-css-grid/ – Dai Feb 19 '22 at 13:58
  • But your items not are square. – Arman Ebrahimi Feb 19 '22 at 14:23
  • @ArmanEbrahimi They are square for me - I've posted a screenshot. How do they appear at your end? – Dai Feb 19 '22 at 14:24
  • Sorry I made a mistake. I hope @sal3jfc accepts your answer. – Arman Ebrahimi Feb 19 '22 at 14:32
  • `grid-template-row: 1fr 1fr 1fr` can be shortend to `grid-auto-rows: 1fr` which does the same. YOu even could remove the entire property as the default will also create equal rows because of the `aspect-ratio`. Instead of creating the broder for every single element, you could use the `grid-gap` and use a broder-collapse with `box-shadow` – tacoshy Feb 19 '22 at 15:19
  • @tacoshy You are correct, but for _didactical_ purposes I wanted to demonstrate with explicit row and column definitions, rather than jumping straight to `grid-auto-rows`. – Dai Feb 19 '22 at 15:20
  • @tacoshy `border-collapse` only applies to `display: table` elements, and while `box-shadow` would have the same visual effect, it _feels_ inappropriate to use it for a hard border. – Dai Feb 19 '22 at 15:21
  • 1
    I know that border-collapse only applies to tables. What I ment is that you can emulate it by using box-shadow as border which will only fill out the grid-gap which is the common technique to emulate a border-collapse on a grid. It only requires 2 properties instead of harcoding for every cell: https://codepen.io/tacoshy/pen/JjOLPMO – tacoshy Feb 19 '22 at 15:51
  • @tacoshy Your idea for `box-shadow` was excellent and practical. thanks. – Arman Ebrahimi Feb 20 '22 at 17:04