Drop middle item to new row when its content wraps in CSS Grid

Viewed 80

I've got 3 items as a calendar header that (when there is enough space) should be in 1 row:

 ┌─────────────────────────────────────────┐
 │ Month  |  Title, possibly long  |  Nav  │
 └─────────────────────────────────────────┘
<header class="calHeader">
  <div class="calHeader__month">August 2022</div>
  <div class="calHeader__title">A Dynamic Title</div>
  <div class="calHeader__nav">Prev/Next</div>
</header>

The text in the middle item is a dynamic title and can be variable length.

On smaller screens and/or if the title is long enough to text wrap, I'd like that div to wrap to a new row:

 ┌─────────────────┐
 │ Month   |   Nav │
 │ ─────────────── │
 │ Title, possibly │
 | long            │
 └─────────────────┘

I haven't figured out how to do it, but it sure seems like some combination of auto-fill or grid auto placement would make it possible. I'm also open to flex or changing the HTML if needed. Using media queries isn't an option because the title length is variable/unknown so picking an arbitrary small breakpoint would work for shorter lengths but not longer and vice versa.

2 Answers

Float can do this if you can update your HTML by moving the title and the end. Resize the container to see the result:

.calHeader > *{
  float:left;
  margin: 0 5px;
}

.calHeader__nav {
  float: right;
}

.calHeader {
  overflow: auto;
  border: 1px solid;
  padding: 10px;
  resize: horizontal;
  max-width: 500px;
}
<header class="calHeader">
  <div class="calHeader__month">August 2022</div>
  <div class="calHeader__nav">Prev/Next</div>
  <div class="calHeader__title">A Dynamic Title with long content</div>
</header>

Here's one way to do it with media query, I'm sure there's better grid shorthand but this works. You might also consider flexbox for this as that might be a simpler way to style this component.

Expand the snippet and use the inspector's responsive mode to see the media query effect - top line goes orangered and bottom line goes teal.

Another thought, you could detect the width of the center column and when that reaches a certain length you add the class to alter the grid styling, but media query is probably the best way.

.calHeader {
display: grid;
grid-template-columns: 1fr 2fr 1fr;
border: 1px dotted #999;
}

.calHeader div {
padding: 1em;
}

@media screen and (max-width: 400px){

.calHeader {
grid-template-columns: 1fr 1fr;
}

.calHeader__nav,
.calHeader__month {
grid-row-start: 0;
grid-row-end: 1;
background: teal;
}

.calHeader___month {
grid-row-start: 1;
grid-row-end: 2;
grid-column: 1/2;
}

.calHeader___nav {
grid-row-start: 1;
grid-row-end: 2;
grid-column: 3/4;
}

.calHeader__title {
  background: orangered;
  grid-row-start: 1;
  grid-row-end: 2;
  grid-column: 1 / 4;
}
}
<header class="calHeader">
  <div class="calHeader__month">August 2022</div>
  <div class="calHeader__title">A Dynamic Title</div>
  <div class="calHeader__nav">Prev/Next</div>
</header>

Related