Flexbox, responsive grid of square divs maintaining aspect ratio
Asked Answered
S

4

8

I'm trying to create a 2x2 grid with divs. Some of the divs might contain an image, but it will probably be set as a background, with the option background-size: cover.

Here's the pen I created: http://codepen.io/qarlo/pen/vLEprq

.container {
  display: flex;
  flex-wrap: wrap;
  justify-content: space-between;
  margin: auto;
  max-width: 960px;
  width: 80%;
}
.container__item {
  align-content: center;
  border: 1px solid #333;
  display: flex;
  flex-basis: 1;
  font-size: 3em;
  justify-content: center;
  height: 100%;
  margin-bottom: 1em;
  min-height: 300px;
  width: 47%;
}
<div class="container">
  <div class="container__item">?</div>
  <div class="container__item">?</div>
  <div class="container__item">?</div>
  <div class="container__item">?</div>
</div>

I'd like to force the divs to be squares and maintain the aspect ratio when resizing it. I was mistakenly hoping that this would have been straightforward with flexbox, but unless I'm missing something, I was wrong.

Sempach answered 8/12, 2015 at 9:27 Comment(1)
@SalmanA, thanks, but it doesn't work on Firefox and even it seems to be working on Chrome, I lose the alignment of the contentSempach
L
14

To maintain your items aspect ratio, a very simple method is to use CSS Viewport units

I modified your pen to see how this units work: http://codepen.io/vladbicu/pen/wMBmOb

.container {
    display: flex;
    flex-wrap: wrap;
    justify-content: space-between;
    margin: auto;
    max-width: 960px;
    width: 80%;
}

.container__item {
    align-content: center;
    border: 1px solid #333;
    display: flex;
    flex-basis: 1;
    font-size: 3em;
    justify-content: center;
    margin-bottom: 1em;

    // maintain aspect ratio
    width: 30vw;
    height: 30vw;
}

Hope it helps.

Lifework answered 8/12, 2015 at 12:33 Comment(4)
This is very nice, but this way it seems that align-content: center doesn't work anymore, does it?Sempach
If you want to vertical align your content, use align-items: center on container__item div. Check this blog post to see the difference between align-content and align-items.Maltz
I actually knew the difference but I was using the other by mistake. Well, this is great and I think is the best solution. Thank youSempach
Flex-basis do not be 1. Check documentation developer.mozilla.org/en-US/docs/Web/CSS/flex-basisSidsida
H
5

Use the old "padding-bottom" trick for fixed aspect ratio. Extra divs are reqiured though:

.container {
  margin: auto;
  width: 80%;
  max-width: 960px;
}
.container__square {
  float: left;
  position: relative;
  padding-bottom: 50%;
  width: 50%;
  background: linear-gradient(45deg, #CCC, #000, #CCC);
}
.container__square__item {
  position: absolute;
  top: 1em;
  bottom: 1em;
  left: 1em;
  right: 1em;
  border: 1px solid #333;
  background: #FFF;
}
/* clearfix */
.container::after {
  content: "";
  display: block;
  clear: both;
}
<div class="container">
  <div class="container__square">
    <div class="container__square__item">?</div>
  </div>
  <div class="container__square">
    <div class="container__square__item">?</div>
  </div>
  <div class="container__square">
    <div class="container__square__item">?</div>
  </div>
  <div class="container__square">
    <div class="container__square__item">?</div>
  </div>
</div>
Heddi answered 8/12, 2015 at 9:56 Comment(2)
this works, is a nice solution, but it's not using flexbox. so I guess flexbox properties are simply not enough (yet?) to solve this problemSempach
@Sempach there is no flexbox solution in my knowledge. Still you can use flexbox for .container and .container__square instead of floats. I used floats because its old school much like the padding trick.Heddi
T
1

Guess you would have to set at least the min-height to maintain the aspect ration on re-size, if you want to go with a flex-box layout.

Here is a quick and dirty example.

function setCellsMinHeight (parentSelector, cellsMargin, aspect) {
  var winWidth = window.innerWidth,
      containerList = document.querySelectorAll(parentSelector),
      containerArray = Array.prototype.slice.call(containerList),
      childMargin = cellsMargin;

  containerArray.forEach(function(elem) {
    var containerWidth = elem.offsetWidth,
        childCount = elem.children.length,
        childWidth = (containerWidth - ((childMargin * 2) * childCount)) / childCount,
        childMinHeight = (childWidth / 100) * aspect;
    for (i = 0; i < childCount; i++) {
      elem.children[i].style.margin = childMargin + "px";
      elem.children[i].style.minHeight = childMinHeight + "px";
    }
  });
}

window.onresize = function(event) {
  setCellsMinHeight('.container', 4, 100);
};

setCellsMinHeight('.container', 4, 100);
body {
  margin: 0;
}
.container {
  display: flex;
  flex-flow: row wrap;
  align-items: stretch;
  max-width: 100%;
  margin: 0 auto;
}

.content-cell {
  flex: 1;
  background-color: #ccc;
}

@media (min-width: 801px) {
  .container {
    max-width: 800px;
  }
}
<div class="container">
  <div class="content-cell"></div>
  <div class="content-cell"></div>
</div>

<div class="container">
  <div class="content-cell"></div>
  <div class="content-cell"></div>
</div>

Hope it helps.

Tobacconist answered 8/12, 2015 at 10:23 Comment(1)
thanks for the script, it seems to work, but again: the main reason I wanted to implement a flexbox solution was to avoid tricky workarounds and rely just on flexbox, but it seems it's still not possibleSempach
R
-1

As i understand i think you want flexible boxes all the time so you can perform this action by using JavaScript.

  1. Find the Highest height of the content
  2. assign that highest width and height for the whole classes

and that's how you can maintain flexible boxes

or you can use external library

  1. Css tricks
  2. JQuery Flexbox
Rania answered 8/12, 2015 at 9:39 Comment(3)
setting the highest height of the content to all elements wouldn't make them responsive, though. Also, from my example, you can see that the content can also be just a character. The css tricks article is just a tutorial on flexbox, isn't it?Sempach
Yeah that's what you want right responsive grid with same and square heightRania
But it's not enough to just find the highest height, because it wouldn't adjust automatically on resize.Sempach

© 2022 - 2024 — McMap. All rights reserved.