alexr
alexr

Reputation: 11

CSS Grid layout with double width first item

I'm trying to achieve a Grid-based layout where items will be laid out in a flexible grid, achieved using grid-template-columns: repeat(auto-fill, minmax(400px, 1fr)). Items then get auto-placed into the grid, which works well.

I'd like the first item to be double-width, so it spans two columns. This is pretty easy to achieve using a rule like this:

.grid > *:first-child {
  grid-column: 1/span 2;
}

However, this causes a problem once there's not enough space to fit two columns in – a second small column still appears, smaller than our minimum of 400px, and this ruins the nice regular grid on the second row onwards. My understanding is that the span 2 essentially forces the algorithm to create an extra column. Is there any option short of using JS to measure the grid container and add and remove the span 2 when there's not enough room? This grid will be used on multiple pages at different widths, so I can't just use a media query to enable/disable this behaviour.

Here's the code to reproduce the problem:

.grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(400px, 1fr));
  grid-auto-columns: none;
  grid-auto-rows: 300px;
}

.item {
  background-color: palegreen;
  border: 1px solid black;
}

.grid > *:first-child {
  background-color: lightcyan;
  grid-column: 1/span 2
}
<div class="grid">
  <div class="item">1</div>
  <div class="item">2</div>
  <div class="item">3</div>
  <div class="item">4</div> 
  <div class="item">5</div>
  <div class="item">6</div>
  <div class="item">7</div>
  <div class="item">8</div>
</div>

See this CodePen for a live example of the problem (resize the viewport to around 700px to see it).

Upvotes: 1

Views: 2334

Answers (1)

Richard Deeming
Richard Deeming

Reputation: 31248

The simple solution would be to move the column rule into a media query. You'd need to account for the margin/padding on the document and any ancestors - on my computer, that seems to be 8px, so a min-width: 816px query works.

*,
::before,
::after {
  box-sizing: border-box;
}

html,
body {
  margin: 0;
  padding: 0;
}

body {
  padding: 8px;
}

.grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(400px, 1fr));
  grid-auto-rows: 50px;
}

.item {
  background-color: palegreen;
  border: 1px solid black;
}

.grid>*:first-child {
  background-color: lightcyan;
}

@media (min-width: 816px) {
  .grid>*:first-child {
    grid-column: 1/span 2;
  }
}
<div class="grid">
  <div class="item">1</div>
  <div class="item">2</div>
  <div class="item">3</div>
  <div class="item">4</div>
  <div class="item">5</div>
  <div class="item">6</div>
  <div class="item">7</div>
  <div class="item">8</div>
</div>

JSFiddle demo

Upvotes: 1

Related Questions