使用flexbox

时间:2015-09-14 19:22:30

标签: css flexbox

我想使用flexbox(没有媒体查询)实现响应式网格状布局。网格中可以有可变数量的元素。每个项目应具有固定且相等的宽度。项目应与左侧对齐。整个组应该具有相等的左右边距。

看起来应该是这样的:

Expected result

这就是我试图实现它的方式:

.container {
  display: flex;
  flex-wrap: wrap;
  justify-content: flex-start;
  margin: auto;
}
.item {
  height: 200px;
  width: 200px;
  background-color: purple;
  padding: 10px;
  margin: 10px;
}
<div class="container">
  <div class="item">Flex item 1</div>
  <div class="item">Flex item 2</div>
  <div class="item">Flex item 3</div>
  <div class="item">Flex item 4</div>
  <div class="item">Flex item 5</div>
</div>

它不起作用:

Actual result

我希望在容器上设置margin: auto会强制它的宽度恰好足以容纳每行中的最佳项目数。

我知道我可以轻松地使用像Bootstrap或Foundations这样的框架,但我想知道是否也可以使用flexbox。

7 个答案:

答案 0 :(得分:3)

一个非常直接的解决方案是在常规项目的末尾添加许多不可见的零高度项目:

<div class="parent">
  <div class="item">1</div>
  <div class="item">2</div>
  <div class="item">3</div>
  <div class="item">4</div>
  <div class="dummyItem"></div>
  <div class="dummyItem"></div>
  <div class="dummyItem"></div>
  <div class="dummyItem"></div>
</div>

.parent {
  display: flex;
  align-items: center;
  justify-content: center;
  flex-wrap: wrap;
}

.parent .item,
.parent .dummyItem{
  width: 50px;
  height: 50px;
  background: white;
  margin: 5px;
}

.parent .dummyItem {
  height: 0;
}

如果您的最长行可以有n个可见项目,那么您至少需要n-1个虚拟项目才能生效。

唯一有点与此相关的是,如果只有一行,则物品实际上不会居中;相反,它们将(大致)对齐到左侧。

Link to Codepen

答案 1 :(得分:2)

你无法通过开箱即用的Flexbox实现这一目标(至少我没有设法做到这一点)。您可以尝试使用justify-content: center;,但这会让所有人感到温和,你会得到类似的东西:

flexbox centering children

所以我设法找到的唯一解决方案是使用另一个父元素并将所有内容包装在其中。

请参阅此CodePen http://codepen.io/justd/pen/rOeMGZ

我确定你会找到适合你的东西,只是尝试结合不同的CSS技术。

答案 2 :(得分:2)

我没有设法使用flexbox实现此行为。但是CSS Grid非常简单。您需要将justify-content: center应用于容器。

Example on CodePen

答案 3 :(得分:1)

如果在容器上设置了显式宽度,则可以将margin: 0 auto应用于包含元素,因为它不再跨越窗口的整个宽度。

以下是您正在寻找的Codepen示例:http://codepen.io/alexverner/pen/MaExqb

答案 4 :(得分:0)

我认为您只需要为您的网格容器提供某种max-width,那么您的自动边距也应该有效。发生了什么事情是你的容器正在向任何一方扩展100%所以没有什么可以使用汽车保证金。

因此,如果您希望每行最多扩展到3个项目,只需将max-width设置为660(项目宽度+项目边距):

.container {
  max-width: 660px;
  margin: 0 auto;
  display: flex;
  flex-flow: row-wrap;
}
.item {
  width: 200px;
  height: 200px;
  margin: 10px;
}

这是一个Codepen:http://codepen.io/kgrote/pen/qbpGWZ

容器将流畅地膨胀,直到达到其最大宽度,然后居中,同时将其子项保持在左对齐的网格中。随着容器缩小,孩子们将根据需要堆叠。

答案 5 :(得分:0)

你必须使用Javascript来实现这一目标。这是因为即使在没有物品的情况下,flexbox容器也会占据所有宽度。

所以基本上我们正在计算margin-left的所需值以使我们的flexbox项目居中。无论初始标记设置如何,此Javascript都应该有效。

纯Javascript版

// get width of element with margins
function getOuterWidth(el) {
  var styles = window.getComputedStyle(el);
  var margins = parseFloat(styles["marginLeft"]) +
    parseFloat(styles["marginRight"]);

  return Math.ceil(el.getBoundingClientRect().width + margins);
}

// get width of element without paddings
function getContentWidth(el) {
  var styles = window.getComputedStyle(el);
  var paddings = parseFloat(styles["paddingLeft"]) +
    parseFloat(styles["paddingRight"]);

  return Math.ceil(el.getBoundingClientRect().width - paddings);
}

// Get top of element
function getTopOfElement(el) {
  return el.getBoundingClientRect().top;
}

var container = document.querySelector(".container");
var initialMarginLeft = parseFloat(window.getComputedStyle(container)["marginLeft"]);
// getting array of items
var items = Array.prototype.slice.call(document.querySelectorAll(".item"));

function centerItems() {
  if (items.length === 0) return 0;

  // set margin-left to initial value to recalculate it
  container.style.marginLeft = initialMarginLeft + "px";

  var topOfFirstItem = getTopOfElement(items[0]);
  var spaceTakenByElementsOnFirstLine = getOuterWidth(items[0]);

  for (var i = 1; i < items.length; i++) {
    // Break in case we are in second line
    if (getTopOfElement(items[i]) > topOfFirstItem)
      break;
    spaceTakenByElementsOnFirstLine += getOuterWidth(items[i]);
  }

  // Set margin-left to center elements
  var marginLeft = initialMarginLeft + (getContentWidth(container) - spaceTakenByElementsOnFirstLine) / 2;

  container.style.marginLeft = marginLeft + "px";
};

window.addEventListener("resize", centerItems);

centerItems();
.container {
  display: flex;
  flex-wrap: wrap;
}

.item {
  height: 200px;
  width: 200px;
  background-color: purple;
  padding: 10px;
  margin: 10px;
}
<div class="container">
  <div class="item">Flex item 1</div>
  <div class="item">Flex item 2</div>
  <div class="item">Flex item 3</div>
  <div class="item">Flex item 4</div>
  <div class="item">Flex item 5</div>
</div>

jQuery版本

// get width of element with margins
function getOuterWidth(el) {
  return $(el).outerWidth(true);
}

// get width of element without paddings
function getContentWidth(el) {
  return parseFloat($(el).css("width"));
}

function getTopOfElement(el) {
  return $(el).position().top;
}

var $container = $(".container");
var $items = $(".item");
var initialMarginLeft = parseFloat($container.css("margin-left"));

function centerItems() {
  if ($items.length === 0) return 0;

  // set margin-left to initial value to recalculate it
  $container.css("margin-left", initialMarginLeft + "px");

  var topOfFirstItem = getTopOfElement($items[0]);
  var spaceTakenByElementsOnFirstLine = getOuterWidth($items[0]);

  for (var i = 1; i < $items.length; i++) {
    // Break in case we are in second line
    if (getTopOfElement($items[i]) > topOfFirstItem)
      break;
    spaceTakenByElementsOnFirstLine += getOuterWidth($items[i]);
  }

  // Set margin left to center elements
  var marginLeft = initialMarginLeft + (getContentWidth($container) - spaceTakenByElementsOnFirstLine) / 2;

  $container.css("margin-left", marginLeft + "px");
};

$(window).resize(centerItems);

centerItems();
.container {
  display: flex;
  flex-wrap: wrap;
}

.item {
  height: 200px;
  width: 200px;
  background-color: purple;
  padding: 10px;
  margin: 10px;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>

<div class="container">
  <div class="item">Flex item 1</div>
  <div class="item">Flex item 2</div>
  <div class="item">Flex item 3</div>
  <div class="item">Flex item 4</div>
  <div class="item">Flex item 5</div>
</div>

答案 6 :(得分:0)

基本上,您应该将页面的结构设置为左右具有默认边距。使用百分比,而不是以像素为单位的宽度。这样,它将具有响应性,并且在所有设备上看起来都一样好。如果要添加最大宽度,您当然可以这样做。这几乎可以提供您最初想要的结果。没有Javascript。 我也从.container css中删除了两行。由于您在处理项目本身的填充和边距。

.pageLayout {
    margin: 0 auto;
    width: 80%;
    /* add optional max width  */
}

.container {
  display: flex;
  flex-wrap: wrap;
}
.item {
  height: 200px;
  width: 200px;
  background-color: purple;
  padding: 10px;
  margin: 10px;
}
<div class="pageLayout">
  <div class="container">
    <div class="item">Flex item 1</div>
    <div class="item">Flex item 2</div>
    <div class="item">Flex item 3</div>
    <div class="item">Flex item 4</div>
    <div class="item">Flex item 5</div>
  </div>
</div>