6

Wanted: a CSS only solution to enable equal height grid "sections" on a per row basis, that is also responsive.

This diagram hopefully explains the requirement better than the words in this post will:

helpful diagram

The "item grid" should be responsive - in that it can show a different number of cards per row based on viewport width. And within a given row, the equivalent sections should have the same height on a "per row" basis.

In the below HTML & CSS - the item cards are split in to the rows that we need (at the two example break points desktop & mobile) but the content section heights are variable (yuck):

.items {
  max-width: 1200px;
}

.item {
  width: 25%;
  box-sizing: border-box;
  display: inline-block;
  vertical-align: top;
  padding: 0 12px;
  margin: 24px -4px 24px 0;
}

@media (max-width: 600px) {
  .item {
    width: 50%;
  }
}

.item__heading {
  background-color: #d4d0f5;
  padding: 10px;
  text-align: center;
  border: 1px solid #bbbbbb;
}

.item__content {
  padding: 10px;
  border-left: 1px solid #bbbbbb;
  border-right: 1px solid #bbbbbb;
}

.item__price {
  background-color: #e0f6d9;
  padding: 10px;
  text-align: center;
  border: 1px solid #bbbbbb;
}
<div class="items">

  <div class="item">
    <div class="item__heading">
      Item 1
    </div>
    <div class="item__content">
      Some content that is not that long
    </div>
    <div class="item__price">
      £99.99
    </div>
  </div>


  <div class="item">
    <div class="item__heading">
      Item 2
    </div>
    <div class="item__content">
      Some content that is longer than other items on the same row and sets the height of this section
    </div>
    <div class="item__price">
      £69.99
    </div>
  </div>

  <div class="item">
    <div class="item__heading">
      Item 3
    </div>
    <div class="item__content">
      Some content that is not that long
    </div>
    <div class="item__price">
      £69.99
    </div>
  </div>

  <div class="item">
    <div class="item__heading">
      Item 4
    </div>
    <div class="item__content">
      Some content that is not that long
    </div>
    <div class="item__price">
      £109.99
    </div>
  </div>

  <div class="item">
    <div class="item__heading">
      Item 5
    </div>
    <div class="item__content">
      Some content that is a medium kind of length blah blah
    </div>
    <div class="item__price">
      £29.99
    </div>
  </div>

  <div class="item">
    <div class="item__heading">
      Item 6
    </div>
    <div class="item__content">
      Some content that is not that long
    </div>
    <div class="item__price">
      £99.99
    </div>
  </div>

    
</div>

The following codepen is a JavaScript based solution that achieves the desired outcome - but is what I am trying to avoid: https://codepen.io/rusta/pen/KmbVKd

Limitations

  • The number of items to be displayed in the grid list can be any number from 1-150
  • The size of the item content to be displayed will be genuinely variable (so picking a "sensible" min-height is not an option)

I was hoping that the new CSS Grid system would help me achieve the above, but having played with it for a while it seems to need a bit more structure than I had hoped it would, and the responsive aspect seemed rather challenging. But maybe there is a CSS Grid based answer out there somewhere

Further note: I say a CSS only solution, by which I mean a non-JS solution. If the HTML blocks need to change (order/nesting/class names) to support a non-JS solution that is absolutely fine

In this trivial example - we are only focusing on the "content" section for having "matching heights" - as we can assume the heading and price sections will naturally be the same height. It would be nice to enable "equivalency" across any matching grid section (header/content/price/other) but that can be for another day...

Michael Benjamin
  • 346,931
  • 104
  • 581
  • 701
Russell Winborn
  • 125
  • 2
  • 8
  • did you even try searching for this? a simple search for css equal height grid brings up a ton of options for you to use – Pete May 22 '17 at 14:30
  • did you read my full post or just the title? – Russell Winborn May 22 '17 at 14:38
  • I read the full post, you can achieve what you want using flex - equal height rows that allows for wrapping and any amount of content - did you put in any effort yourself or just ask a question here? – Pete May 22 '17 at 14:40
  • 1
    It's bordering on embarrassing how much time I've spent trying to resolve this as it happens! Hence putting it on here - and with as much detail as possible. I hit a dead end with flexbox a while back – Russell Winborn May 22 '17 at 14:48
  • 1
    note: it's the inner item sections that need to have the same height, not just the item cards themselves - which I think is what went beyond flex-box capabilities (or at least my flex-box capabilities anyway!) – Russell Winborn May 22 '17 at 14:52
  • So show us what you tried with flexbox rather than your js solution, we're here to fix broken code, not offer up whole solutions - try taking time to read the rules of the site to see what is on topic and not. Also we are not mind readers - no where in your question have you mentioned that you tried flex – Pete May 22 '17 at 14:52
  • This would be the closest to a pure css solution you will get: https://codepen.io/anon/pen/VbqKeG the problem being with if the headers or footers are different heights, it eats up into your white space. Other than that you would need to use tables so that all your rows lined up to be the same height - not very responsive though and wouldn't wrap like flex. Your best bet is to stay with a js solution to get even "rows" – Pete May 22 '17 at 15:03
  • 1
    Happy to add that I've tried and failed with flexbox. I did add that I'd tried and failed with CSS Grid. If you don't mind I'd like to keep this question open as it isn't a duplicate of the item you suggested - and I'd be interested to know if anyone else out there can offer a solution (possibly CSS grid based?) – Russell Winborn May 22 '17 at 15:16
  • "same height row sections" and "responsive" are in the title - which are the main goals of the post. The definition of them in this context is non trivial hence I've added a detailed description of the problem in a detailed example – Russell Winborn May 22 '17 at 15:18

1 Answers1

5

By giving the .items display: flex; flex-wrap: wrap; your item will become flex items and flow from left to right and wrap when there is no more space.

Then you give the .item display: flex; flex-direction: column;, which will make them a flex container as well, and by using column direction, its children will flow vertically, like block elements.

Finally you give the .item__content flex: 1;, which will make it take any remaining space, vertically, hence every row's item will have equal height.

Updated codepen

Stack snippet

.items {
  display: flex;
  flex-wrap: wrap;
  max-width: 1200px;
}

.item {
  display: flex;
  flex-direction: column;
  width: 25%;
  box-sizing: border-box;
  vertical-align: top;
  padding: 0 12px;
  margin: 24px -4px 24px 0;
}

@media (max-width: 600px) {
  .item {
    width: 50%;
  }
}

.item__heading {
  background-color: #d4d0f5;
  padding: 10px;
  text-align: center;
  border: 1px solid #bbbbbb;
}

.item__content {
  flex: 1 1 auto;                   /* IE need 1 1 auto */
  padding: 10px;
  border-left: 1px solid #bbbbbb;
  border-right: 1px solid #bbbbbb;
}

.item__price {
  background-color: #e0f6d9;
  padding: 10px;
  text-align: center;
  border: 1px solid #bbbbbb;
}
<div class="items">

  <div class="item">
    <div class="item__heading">
      Item 1
    </div>
    <div class="item__content">
      Some content that is not that long
    </div>
    <div class="item__price">
      £99.99
    </div>
  </div>

  <div class="item">
    <div class="item__heading">
      Item 2
    </div>
    <div class="item__content">
      Some content that is longer than other items on the same row and sets the height of this section
    </div>
    <div class="item__price">
      £69.99
    </div>
  </div>

  <div class="item">
    <div class="item__heading">
      Item 3
    </div>
    <div class="item__content">
      Some content that is not that long
    </div>
    <div class="item__price">
      £69.99
    </div>
  </div>

  <div class="item">
    <div class="item__heading">
      Item 4
    </div>
    <div class="item__content">
      Some content that is not that long
    </div>
    <div class="item__price">
      £109.99
    </div>
  </div>

  <div class="item">
    <div class="item__heading">
      Item 5
    </div>
    <div class="item__content">
      Some content that is a medium kind of length blah blah
    </div>
    <div class="item__price">
      £29.99
    </div>
  </div>

  <div class="item">
    <div class="item__heading">
      Item 6
    </div>
    <div class="item__content">
      Some content that is not that long
    </div>
    <div class="item__price">
      £99.99
    </div>
  </div>

</div>
Asons
  • 84,923
  • 12
  • 110
  • 165
  • thanks for your answer. I was about to edit the question to account for "multiple" sections as per this JS codepen http://codepen.io/rusta/pen/xdmdxm (so the content and feature sections will have a matching height per row). I'm not sure a flex-box solution would extend to this? – Russell Winborn May 22 '17 at 19:43
  • @RussellWinborn No, that won't be possible with Flexbox alone, you'll need a script to get the height of the `.item__features` element, ...and that can be done with quite a simple script that simply loops the elements, get the highest and create a style element dynamically, matching that rule with the height. And since its done once per page load, no big deal performance wise – Asons May 22 '17 at 19:56
  • I've created a [new question](https://stackoverflow.com/questions/44129135/css-only-solution-to-set-multiple-same-height-row-sections-on-a-responsive-gri) for my extended "multiple section" requirement as I'm hoping a CSS solution is out there somewhere (or at least will be one day) – Russell Winborn May 23 '17 at 08:06