skip to Main Content

My aim is to create a 3 by 3 grid made of squares, which adjust to the size of the content, have corner numbers, and whose text content is centred both vertically and horizontally. After hours upon hours of attempting different ways to solve this issue, I’m left with a compromise between square cells and overflowing outside the container. I’ve tried different ways to achieve the 1:1 aspect ratio, but the methods haven’t been compatible with my html + css. Height and width are deliberately not set to any specific values to enable the dynamic size of the cells and grid.

The first snippet shows a grid with squares, with a corner number. The only problem is that the content overflows. The grid container has to have position relative because of a label that goes next to the grid positioned with ‘absolute’, and which I could not include here.

The second snippet has the only difference that the ‘aspect-ratio: 1’ has been removed. The cells of the grid do not overflow the grid anymore, but they are not square either.

Is there a way to have square grid cells which adjust to content width and height without overflowing?

.basic-text {
     font-size: larger;
     font-family: Arial, Helvetica, sans-serif;
}
.fancy-card {
     border: 3px solid grey;
     border-radius: 15px;
     margin: 1em;
}
#output-card {
     display: inline-block;
     vertical-align: top;
}
#output-grid-container {
     margin: 1em;
     padding: 2em;
     position: relative;
     background-color: white;
     display: grid;
     grid-template-columns: repeat(3, 1fr);
     grid-template-rows: repeat(3, 1fr);
     gap: 20px;
}
.grid-square {
     position: relative;
     border: 2px solid grey;
     border-radius: 3px;
     padding: 1em;
     aspect-ratio: 1;
     display: flex;
     justify-content: center;
    /* Center horizontally */
     align-items: center;
    /* Center vertically */
     text-align: center;
     line-height: 150%;
}
p {
     white-space: pre;
     text-wrap: wrap;
}
.corner-rating-number {
     position: absolute;
     bottom: 0.1em;
     left: 0.3em;
     margin: 0;
     padding: 0;
}
select {
     height: 2em;
     width: 10em;
     border-radius: 0.5em;
}
<div class="fancy-card" id="output-card">
  <div id="output-grid-container">
    <div class="grid-square">
      <span class="corner-rating-number basic-text">7</span>
      <p class="basic-text"></p>
    </div>
    <div class="grid-square">
      <span class="corner-rating-number basic-text">8</span>
      <p class="basic-text">Pink</p>
    </div>
    <div class="grid-square">
      <span class="corner-rating-number basic-text">9</span>
      <p class="basic-text"></p>
    </div>
    <div class="grid-square">
      <span class="corner-rating-number basic-text">4</span>
      <p class="basic-text"></p>
    </div>
    <div class="grid-square">
      <span class="corner-rating-number basic-text">5</span>
      <p class="basic-text">Violet</p>
    </div>
    <div class="grid-square">
      <span class="corner-rating-number basic-text">6</span>
      <p class="basic-text"></p>
    </div>
    <div class="grid-square">
      <span class="corner-rating-number basic-text">1</span>
      <p class="basic-text"></p>
    </div>
    <div class="grid-square">
      <span class="corner-rating-number basic-text">2</span>
      <p class="basic-text"></p>
    </div>
    <div class="grid-square">
      <span class="corner-rating-number basic-text">3</span>
      <p class="basic-text">Blue<br><br>Green</p>
    </div>
  </div>
</div>
.basic-text {
     font-size: larger;
     font-family: Arial, Helvetica, sans-serif;
}
.fancy-card {
     border: 3px solid grey;
     border-radius: 15px;
     margin: 1em;
}
#output-card {
     display: inline-block;
     vertical-align: top;
}
#output-grid-container {
     margin: 1em;
     padding: 2em;
     position: relative;
     background-color: white;
     display: grid;
     grid-template-columns: repeat(3, 1fr);
     grid-template-rows: repeat(3, 1fr);
     gap: 20px;
}
.grid-square {
     position: relative;
     border: 2px solid grey;
     border-radius: 3px;
     padding: 1em;
     display: flex;
     justify-content: center;
    /* Center horizontally */
     align-items: center;
    /* Center vertically */
     text-align: center;
     line-height: 150%;
}
p {
     white-space: pre;
     text-wrap: wrap;
}
.corner-rating-number {
     position: absolute;
     bottom: 0.1em;
     left: 0.3em;
     margin: 0;
     padding: 0;
}
select {
     height: 2em;
     width: 10em;
     border-radius: 0.5em;
}
<div class="fancy-card" id="output-card">
  <div id="output-grid-container">
    <div class="grid-square">
      <span class="corner-rating-number basic-text">7</span>
      <p class="basic-text"></p>
    </div>
    <div class="grid-square">
      <span class="corner-rating-number basic-text">8</span>
      <p class="basic-text">Pink</p>
    </div>
    <div class="grid-square">
      <span class="corner-rating-number basic-text">9</span>
      <p class="basic-text"></p>
    </div>
    <div class="grid-square">
      <span class="corner-rating-number basic-text">4</span>
      <p class="basic-text"></p>
    </div>
    <div class="grid-square">
      <span class="corner-rating-number basic-text">5</span>
      <p class="basic-text">Violet</p>
    </div>
    <div class="grid-square">
      <span class="corner-rating-number basic-text">6</span>
      <p class="basic-text"></p>
    </div>
    <div class="grid-square">
      <span class="corner-rating-number basic-text">1</span>
      <p class="basic-text"></p>
    </div>
    <div class="grid-square">
      <span class="corner-rating-number basic-text">2</span>
      <p class="basic-text"></p>
    </div>
    <div class="grid-square">
      <span class="corner-rating-number basic-text">3</span>
      <p class="basic-text">Blue<br><br>Green</p>
    </div>
  </div>
</div>

2

Answers


  1. Chosen as BEST ANSWER

    I solved this by keeping aspect-ratio: 1 on the squares, and checking what size the squares become. Then I set the column width explicitly to match the current size. This explicitly set size of the squares makes the outer div adjust to the inner size. Relevant code is in the snippet below.

    If the page is supposed to update reactively, do this: when data for the grid is updated, set flag squareDimensionsNeedUpdate truthy. Before DOM update, if flag is truthy, grid-template-columns has to be set back to repeat(3, 1fr) in order for the squares to adjust to new contents. After the update, if flag is truthy, set flag falsy, and get and set the grid column width.

    let outputGridContainer = document.getElementById('output-grid-container');
    let firstGridSquare = outputGridContainer.querySelector('.grid-square');
    let firstGridSquareDimensions = firstGridSquare.getBoundingClientRect();
    let firstGridSquareWidth = firstGridSquareDimensions.width;
    outputGridContainer.style.gridTemplateColumns = `repeat(3, ${firstGridSquareWidth}px)`;
    .basic-text {
         font-size: larger;
         font-family: Arial, Helvetica, sans-serif;
    }
    .fancy-card {
         border: 3px solid grey;
         border-radius: 15px;
         margin: 1em;
    }
    #output-card {
         display: inline-block;
         vertical-align: top;
    }
    #output-grid-container {
         margin: 1em;
         padding: 2em;
         position: relative;
         background-color: white;
         display: grid;
         grid-template-columns: repeat(3, 1fr);
         grid-template-rows: repeat(3, 1fr);
         gap: 20px;
    }
    .grid-square {
         position: relative;
         border: 2px solid grey;
         border-radius: 3px;
         padding: 1em;
         aspect-ratio: 1;
         display: flex;
         justify-content: center;
        /* Center horizontally */
         align-items: center;
        /* Center vertically */
         text-align: center;
         line-height: 150%;
    }
    p {
         white-space: pre;
         text-wrap: wrap;
    }
    .corner-rating-number {
         position: absolute;
         bottom: 0.1em;
         left: 0.3em;
         margin: 0;
         padding: 0;
    }
    select {
         height: 2em;
         width: 10em;
         border-radius: 0.5em;
    }
    <div class="fancy-card" id="output-card">
      <div id="output-grid-container">
        <div class="grid-square">
          <span class="corner-rating-number basic-text">7</span>
          <p class="basic-text"></p>
        </div>
        <div class="grid-square">
          <span class="corner-rating-number basic-text">8</span>
          <p class="basic-text">Pink</p>
        </div>
        <div class="grid-square">
          <span class="corner-rating-number basic-text">9</span>
          <p class="basic-text"></p>
        </div>
        <div class="grid-square">
          <span class="corner-rating-number basic-text">4</span>
          <p class="basic-text"></p>
        </div>
        <div class="grid-square">
          <span class="corner-rating-number basic-text">5</span>
          <p class="basic-text">Violet</p>
        </div>
        <div class="grid-square">
          <span class="corner-rating-number basic-text">6</span>
          <p class="basic-text"></p>
        </div>
        <div class="grid-square">
          <span class="corner-rating-number basic-text">1</span>
          <p class="basic-text"></p>
        </div>
        <div class="grid-square">
          <span class="corner-rating-number basic-text">2</span>
          <p class="basic-text"></p>
        </div>
        <div class="grid-square">
          <span class="corner-rating-number basic-text">3</span>
          <p class="basic-text">Blue<br><br>Green</p>
        </div>
      </div>
    </div>


  2. You ask "Is there a way to have square grid cells that adjust to the width and height of the content without overflowing?", but aspect-ratio is about the width-to-height ratio… So under normal conditions you you will not be able to get a square when the height is greater than the width.
    So all that can be done that .grid-square does not stretch and are squares…The easiest way, is to add overflow: hidden; or min-width: 0; minimum height: 0;:

    .basic-text {
         font-size: larger;
         font-family: Arial, Helvetica, sans-serif;
    }
    .fancy-card {
         border: 3px solid grey;
         border-radius: 15px;
         margin: 1em;
    }
    #output-card {
         display: inline-block;
         vertical-align: top;
    }
    #output-grid-container {
         margin: 1em;
         padding: 2em;
         position: relative;
         background-color: white;
         display: grid;
         grid-template-columns: repeat(3, 1fr);
         grid-template-rows: repeat(3, 1fr);
         gap: 20px;
    }
    .grid-square {
         position: relative;
         border: 2px solid grey;
         border-radius: 3px;
         padding: 1em;
         aspect-ratio: 1;
         display: flex;
         justify-content: center;
        /* Center horizontally */
         align-items: center;
        /* Center vertically */
         text-align: center;
         line-height: 150%;
         
         overflow: hidden;
         /* min-width: 0; */
         /* min-height:0; */
    }
    p {
         white-space: pre;
         text-wrap: wrap;
    }
    .corner-rating-number {
         position: absolute;
         bottom: 0.1em;
         left: 0.3em;
         margin: 0;
         padding: 0;
    }
    select {
         height: 2em;
         width: 10em;
         border-radius: 0.5em;
    }
    <div class="fancy-card" id="output-card">
      <div id="output-grid-container">
        <div class="grid-square">
          <span class="corner-rating-number basic-text">7</span>
          <p class="basic-text"></p>
        </div>
        <div class="grid-square">
          <span class="corner-rating-number basic-text">8</span>
          <p class="basic-text">Pink</p>
        </div>
        <div class="grid-square">
          <span class="corner-rating-number basic-text">9</span>
          <p class="basic-text"></p>
        </div>
        <div class="grid-square">
          <span class="corner-rating-number basic-text">4</span>
          <p class="basic-text"></p>
        </div>
        <div class="grid-square">
          <span class="corner-rating-number basic-text">5</span>
          <p class="basic-text">Violet</p>
        </div>
        <div class="grid-square">
          <span class="corner-rating-number basic-text">6</span>
          <p class="basic-text"></p>
        </div>
        <div class="grid-square">
          <span class="corner-rating-number basic-text">1</span>
          <p class="basic-text"></p>
        </div>
        <div class="grid-square">
          <span class="corner-rating-number basic-text">2</span>
          <p class="basic-text"></p>
        </div>
        <div class="grid-square">
          <span class="corner-rating-number basic-text">3</span>
          <p class="basic-text">Blue<br><br>Green</p>
        </div>
      </div>
    </div>
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search