左对齐和居中网格与flexbox

Dor*_*ska 16 css flexbox

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

看起来应该是这样的:

预期结果

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

.container {
  display: flex;
  flex-wrap: wrap;
  justify-content: flex-start;
  margin: auto;
}
.item {
  height: 200px;
  width: 200px;
  background-color: purple;
  padding: 10px;
  margin: 10px;
}
Run Code Online (Sandbox Code Playgroud)
<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>
Run Code Online (Sandbox Code Playgroud)

它不起作用:

实际结果

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

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

Vad*_*kov 6

CSS 网格

CSS Grid 解决方案是唯一优雅且灵活的 CSS 解决方案。

.container {
  display: grid;
  grid-template-columns: repeat(auto-fill, 200px);
  grid-auto-rows: 200px;
  grid-gap: 10px;
  justify-content: center;
}

.item {
  background-color: purple;
  padding: 10px;
}
Run Code Online (Sandbox Code Playgroud)
<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>
Run Code Online (Sandbox Code Playgroud)

不幸的是,它没有最好的浏览器支持,所以如果你需要像 IE 这样过时的浏览器,你将不得不使用 Javascript 来实现这一点。这是因为 flexbox 容器占据了所有宽度,即使在项目没有的情况下也是如此。

纯 Javascript 版本

所以基本上我们正在计算需要的值来margin-left使我们的 flexbox 项目居中。无论初始标记设置如何,此 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();
Run Code Online (Sandbox Code Playgroud)
.container {
  display: flex;
  flex-wrap: wrap;
}

.item {
  height: 200px;
  width: 200px;
  background-color: purple;
  padding: 10px;
  margin: 10px;
}
Run Code Online (Sandbox Code Playgroud)
<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>
Run Code Online (Sandbox Code Playgroud)

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();
Run Code Online (Sandbox Code Playgroud)
.container {
  display: flex;
  flex-wrap: wrap;
}

.item {
  height: 200px;
  width: 200px;
  background-color: purple;
  padding: 10px;
  margin: 10px;
}
Run Code Online (Sandbox Code Playgroud)
<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>
Run Code Online (Sandbox Code Playgroud)


小智 2

你无法使用开箱即用的 Flexbox 来实现这一点(至少我没能做到)。您可以尝试使用,justify-content: center;但这将使所有孩子居中,您会得到类似的结果:

弹性盒子居中儿童

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

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

我相信您会找到适合您的东西,只需尝试结合不同的 CSS 技术即可。

  • 谢谢@justd,我尝试了这个解决方案,但我的目标是实现与第一张图片完全相同的布局。 (5认同)