thenickman100
thenickman100

Reputation: 51

How to create responsive and perfectly rectangular grids?

Working Demo

Here is a demo of responsive, perfectly rectangular grids in CSS. No matter the width of the screen, the grid will always form a perfect rectangle.

body {
  max-width: 900px;
}

.grid-1 {
  display: grid;
  grid-template-columns: repeat(auto-fill, 100px);
  gap: 5px;
  max-width: 100%;
  width: fit-content;
  overflow: hidden;
}

.grid-1>* {
  background-color: green;
  width: 100px;
  height: 100px;
}

.grid-2 {
  display: grid;
  grid-template-columns: repeat(auto-fill, 100px);
  gap: 5px;
  width: 1000px;
}

.grid-2>* {
  background-color: red;
  width: 100px;
  height: 100px;
}
<div class="grid-1">
  <div></div>
  <div></div>
  <div></div>
  <div></div>
  <div></div>
  <div></div>
  <div></div>
  <div></div>
  <div></div>
  <div></div>
  <div></div>
  <div></div>
  <div></div>
  <div></div>
  <div></div>
  <div></div>
  <div class="grid-2">
    <div></div>
    <div></div>
    <div></div>
    <div></div>
    <div></div>
    <div></div>
    <div></div>
    <div></div>
  </div>
</div>

Screenshot:

Approach 1, no grid overflow, pic 3

Broken Demo

The problem I encounter happens when I make my columns/rows 1/2 the size and have the grid items occupy 2 rows and 2 columns.

In this second demo, certain window widths will cause the last item in the grid to be a half cell, and that breaks the perfect rectangle.

body {
  max-width: 900px;
}

.grid-1 {
  display: grid;
  grid-template-columns: repeat(auto-fill, 50px);
  grid-template-rows: repeat(auto-fill, 50px);
  gap: 5px;
  max-width: 100%;
  width: fit-content;
  overflow: hidden;
}

.grid-1>* {
  background-color: green;
  width: 100px;
  height: 100px;
  grid-column: span 2;
  grid-row: span 2;
}

.grid-2 {
  display: grid;
  grid-template-columns: repeat(auto-fill, 100px);
  gap: 10px;
  width: 1000px;
}

.grid-2>* {
  background-color: red;
  width: 100px;
  height: 100px;
}
<div class="grid-1">
  <div></div>
  <div></div>
  <div></div>
  <div></div>
  <div></div>
  <div></div>
  <div></div>
  <div></div>
  <div></div>
  <div></div>
  <div></div>
  <div></div>
  <div></div>
  <div></div>
  <div></div>
  <div></div>
  <div class="grid-2">
    <div></div>
    <div></div>
    <div></div>
    <div></div>
    <div></div>
    <div></div>
    <div></div>
    <div></div>
  </div>
</div>

With this second approach, half of the time, there will be half-width red grid item as the very last item in the overall grid. Is there a way I can eliminate this and make a responsive, perfect rectangle when using these half-step grids?

Screenshot:

Approach 2, grid overflow

Is there a better approach to solve this issue that uses pure CSS? My grid-ception feels like a slightly janky approach.

EDIT: I need to retain all of the half columns and not restrict the column count to 2N.

EDIT 2: Detailed Demo

Here is a more detailed demo showing why I want the half-grid steps. I would like a tile in the upper right corner that has a visible gap separating it from the other tiles. By using half-grid steps, I can reduce the size of the separation gap without sacrificing additional columns that the green/red tiles would be able to fill.

        :root {
            --grid-gap: 0.4rem;
            --grid-division: 2; /*Integer*/
            --tile-base-size: 9.5rem;
            --tile-size: calc(
                var(--tile-base-size) - (
                    (var(--grid-division) - 1) 
                    * var(--grid-gap)
                )
            );
        }

        .overlay {
            grid-column-start: calc(-1 - var(--grid-division));
            grid-column-end: -1;
            grid-row-start: 1;
            grid-row-end: calc(1 + var(--grid-division));
            background-color: blue;
        }

        .filler {
            grid-column-start: calc(-2 - var(--grid-division));
            grid-column-end: -1;
            grid-row-start: 1;
            grid-row-end: calc(1 + 2 * var(--grid-division));
        }

        body {
            max-width: 900px;
        }

        .grid-1 {
            display: grid;
            grid-template-columns: repeat(auto-fill, calc(var(--tile-size)/var(--grid-division)));
            gap: var(--grid-gap);
            max-width: 100%;
            width: fit-content;
            overflow: hidden;
            margin: 0 auto;
        }

        .tile {
            background-color: green;
            width: var(--tile-base-size);
            height: auto;
            aspect-ratio: 1;
            grid-column: span var(--grid-division);
            grid-row: span var(--grid-division);
        }

        .grid-2 {
            display: inline-grid;
            grid-template-columns: repeat(auto-fill, calc(var(--tile-base-size)));
            column-gap: calc(var(--grid-gap));
            justify-content: start;
            width: 1000px;
            height: var(--tile-base-size);
            grid-row: span var(--grid-division);
            overflow: hidden;
        }

        .grid-2 > * {
            background-color: red;
            width: 100%;
            height: auto;
            aspect-ratio: 1;
        }
<div class="grid-1">
        <div class="tile"></div>
        <div class="tile"></div>
        <div class="tile"></div>
        <div class="tile"></div>
        <div class="tile"></div>
        <div class="tile"></div>
        <div class="tile"></div>
        <div class="tile"></div>
        <div class="tile"></div>
        <div class="tile"></div>
        <div class="tile"></div>
        <div class="tile"></div>
        <div class="tile"></div>
        <div class="tile"></div>
        <div class="tile"></div>
        <div class="tile"></div>
        <div class="grid-2">
            <div></div>
            <div></div>
            <div></div>
            <div></div>
            <div></div>
            <div></div>
            <div></div>
            <div></div>
        </div>
        <div class="filler"></div>
        <div class="overlay"></div>
    </div>

Upvotes: 0

Views: 91

Answers (0)

Related Questions