Flexbox, responsive grid of square divs maintaining aspect ratio

15,669

Solution 1

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.

Solution 2

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>

Solution 3

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.

Share:
15,669
Carlo
Author by

Carlo

Updated on June 24, 2022

Comments

  • Carlo
    Carlo about 2 years

    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.

  • Carlo
    Carlo over 8 years
    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?
  • Om Komawar
    Om Komawar over 8 years
    Yeah that's what you want right responsive grid with same and square height
  • Carlo
    Carlo over 8 years
    But it's not enough to just find the highest height, because it wouldn't adjust automatically on resize.
  • Carlo
    Carlo over 8 years
    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 problem
  • Carlo
    Carlo over 8 years
    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 possible
  • Salman A
    Salman A over 8 years
    @Carlo 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.
  • Carlo
    Carlo over 8 years
    This is very nice, but this way it seems that align-content: center doesn't work anymore, does it?
  • Vlad Bîcu
    Vlad Bîcu over 8 years
    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.
  • Carlo
    Carlo over 8 years
    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 you
  • Steven Mouret
    Steven Mouret over 7 years
    Flex-basis do not be 1. Check documentation developer.mozilla.org/en-US/docs/Web/CSS/flex-basis