Flexbox,响应式正方形div格栅保持宽高比

8
我正在尝试创建一个包含div的2x2网格。其中一些div可能包含图像,但它可能会被设置为背景,并采用 background-size: cover 选项。
这是我创建的笔记本链接: 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>

我想让div成为正方形,并在调整大小时保持纵横比。我错误地以为这可以通过flexbox轻松实现,但除非我错过了什么,否则我是错误的。

@SalmanA,谢谢你的帮助,但是它在Firefox上无法工作,即使在Chrome上似乎可以工作,我也失去了内容的对齐。 - Carlo
4个回答

14
为了保持您的项目宽高比,一个非常简单的方法是使用CSS视口单位
我修改了您的代码以查看这些单位的工作方式: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;
}

希望它有所帮助。

这很好,但是这样似乎align-content: center就不再起作用了,是吗? - Carlo
如果您想要垂直对齐您的内容,请在 container__item div 上使用 align-items: center。查看此博客文章,了解 align-content 和 align-items 之间的区别。 - Vlad Bîcu
我其实知道区别,但是我一直在错误地使用另一个。好的,这很棒,我认为这是最好的解决方案。谢谢。 - Carlo
Flex-basis不要设为1。请查看文档https://developer.mozilla.org/en-US/docs/Web/CSS/flex-basis。 - Steven Mouret

5

使用旧的“padding-bottom”技巧来实现固定宽高比。但需要额外的div:

.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>


这个方案可行且不错,但它并没有使用flexbox。因此我猜想flexbox属性还不足以解决这个问题(尚未?)。 - Carlo
@Carlo,据我所知,目前没有flexbox的解决方案。但你仍然可以使用flexbox来代替浮动来处理.container和.container__square。我使用浮动是因为它很老派,就像padding trick一样。 - Salman A

1

如果您想使用 flex-box 布局来保持宽高比,请至少设置 min-height,下面是一个快速而简单的示例。

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>

希望它有所帮助。

感谢您提供的脚本,看起来可以正常工作,但是我想实现flexbox解决方案的主要原因是避免繁琐的解决方法,只依赖于flexbox。但很遗憾似乎仍然不可能。 - Carlo

-1

据我理解,您想始终使用弹性框,因此可以通过使用JavaScript执行此操作。

  1. 查找内容的最大高度
  2. 将该最大宽度和高度分配给整个类

这就是您可以保持弹性框的方法

或者您可以使用外部库

  1. Css tricks
  2. JQuery Flexbox

将内容的最高高度设置为所有元素并不会使它们具有响应性。此外,从我的示例中,您可以看到内容也可以只是一个字符。 CSS Tricks文章只是关于flexbox的教程,不是吗? - Carlo
是的,这就是你想要的,具有响应式网格和相同的正方形高度。 - Om Komawar
但仅仅找到最高的高度是不够的,因为它在调整大小时不会自动调整。 - Carlo

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接