Search code examples
csscss-grid

Pulling grid items inward - "grid squeeze"


My grid layout has 2 columns. It contains a mixture of full-width items, which occupy the full width of the grid; and half-width items, which each occupy half the width of a row. Half-width items always come in pairs. The leftmost item should be pulled to the right, and the rightmost should be pulled to the left, in effect being squeezed together.

I have prepared an example with Tailwind-style CSS that demonstrates what I want:

.m-2 { margin: 0.5rem; }
.p-2 { padding: 0.5rem; }
.bg-blue { background-color: rgba(0, 0, 255, 0.5); }
.bg-red { background-color: rgba(255, 0, 0, 0.5); }

.grid { display: grid; }
.grid-cols-2 { grid-template-columns: repeat(2, minmax(0, 1fr)); }
.col-span-2 { grid-column: span 2 / span 2; }

.justify-self-start { justify-self: start; }
.justify-self-end { justify-self: end; }
<div class="grid grid-cols-2">
  <div class="col-span-2 m-2 p-2 bg-blue">
    <p>Full width item</p>
  </div>
  <div class="justify-self-end m-2 p-2 bg-red">
    <p>Half width item</p>
  </div>
  <div class="justify-self-start m-2 p-2 bg-red">
    <p>Half width item</p>
  </div>
  <div class="col-span-2 m-2 p-2 bg-blue">
    <p>Full width item</p>
  </div>
</div>

However, in my scenario, any individual grid item only knows whether or not it is full-width or half-width. If it is full-width, it can set itself to span 2 columns. If it is half-width, it can set itself to span 1 column, but it doesn't know whether to pull itself to the left or the right.

When an individual item doesn't know if it's the first or second item in a half-width row, how can I tell it to pull itself either to the left or to the right?


Bonus points for a solution that works with 3 items in a row, with the middle one staying in the centre.

Bonus points for a solution that uses grid-auto-flow to position half-width elements next to each other that don't appear consecutively in the HTML.


Solution

  • The only way that I can think of to solve it using only CSS is setting different elements for your layout, and then using nth-of-type:

    .container {
        display: grid;
        grid-template-columns: 200px 200px;
        grid-auto-flow: row dense;
        grid-gap: 4px;
    }
    
    span {
        grid-column: span 2;
        background-color: lightblue;
      
    }
    
    p {
        width: 70px;
        background-color: lightgreen;
    }
    
    p:nth-of-type(odd) {
        justify-self: end;
    }
    <div class="container">
    <span>full</span>
    <span>full</span>
    <p>half</p>
    <span>full</span>
    <p>half</p>
    <p>half</p>
    <span>full</span>
    <p>half</p>
    <p>half</p>
    <p>half</p>
    </div>