2

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.

snazzybouche
  • 2,241
  • 3
  • 21
  • 51

1 Answers1

2

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>
vals
  • 61,425
  • 11
  • 89
  • 138
  • 1
    The fact that this works is absolutely baffling - no matter which way I count it, either visually or by LOC, whether an element is on the left or right seems completely inconsistent other than the fact that they're where I want them to be. As an aside, there's no reason to have to use different tags for this, classes will work fine. – snazzybouche Dec 07 '20 at 01:22
  • I don't think that using classes could work, see https://stackoverflow.com/a/10931957/1926369 – vals Dec 07 '20 at 08:40
  • The solution uses the fact that, since we are packing the element "dense", a "half" element will always be on the left if it is an odd half element, and will always be on the right if it is an even half element – vals Dec 07 '20 at 08:42
  • I've implemented this with classes and `:nth-child(2n+1)` in my application, and it's working fine, though to be fair I've not yet rigorously tested it with `grid-auto-flow`. Re left/right, consider the case with one `full` followed by one `half` - the `half` is the 2nd element any way you count it, so it should be pulled to the left, but somehow it is still pulled to the right. Unless CSS counts a `full` element as 2 for the purposes of `nth-*` selectors, it just doesn't make sense to me. – snazzybouche Dec 07 '20 at 09:24
  • Oh - it just clicked. `p:nth-of-type` is only counting the number of `p` elements, not all the elements. In that case it seems you're right about `nth-of-type` being the only way to do this. Luckily HTML5 provides many different element types to abuse. Thank you! – snazzybouche Dec 07 '20 at 09:26