【问题标题】:Left aligned and centered grid with flexbox使用 flexbox 左对齐和居中的网格
【发布时间】:2015-12-10 21:36:18
【问题描述】:

我想使用 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;
}
<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>

没用:

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

我知道我可以使用 Bootstrap 或 Foundations 等框架轻松实现,但我想知道是否也可以使用 flexbox。

【问题讨论】:

    标签: css flexbox


    【解决方案1】:

    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;
    }
    <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>

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

    纯Javascript版本

    所以基本上我们正在计算所需的margin-left 值以使我们的弹性框项目居中。无论初始标记设置如何,此 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>

    【讨论】:

      【解决方案2】:

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

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

      【讨论】:

        【解决方案3】:

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

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

        请查看此 CodePen http://codepen.io/justd/pen/rOeMGZ

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

        【讨论】:

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

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

        Example on CodePen

        【讨论】:

          【解决方案5】:

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

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

          【讨论】:

            【解决方案6】:

            我认为你只需要给你的网格容器某种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

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

            【讨论】:

              【解决方案7】:

              基本上,您应该在页面结构上设置默认的左右边距。使用百分比,而不是像素宽度。这样它就会有响应,并且看起来应该和所有设备一样好。如果您想添加最大宽度,您当然可以这样做。这将给出您最初想要的结果。没有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>

              【讨论】:

                猜你喜欢
                • 2015-04-26
                • 2017-12-11
                • 1970-01-01
                • 2017-01-16
                • 2020-05-12
                • 1970-01-01
                • 2018-03-16
                • 1970-01-01
                相关资源
                最近更新 更多