如何将弹性容器居中但左对齐弹性项目

How to center a flex container but left-align flex items

我希望 flex 项目居中,但是当我们有第二行时,有 5 个(来自下图)在 1 之下并且不在父项中居中。

这是我的示例:

ul {
  display: flex;
  flex-direction: row;
  flex-wrap: wrap;
  justify-content: center;
  margin: 0;
  padding: 0;
}
li {
  list-style-type: none;
  border: 1px solid gray;
  margin: 15px;
  padding: 5px;
  width: 200px;
}
<ul>
  <li>1</li>
  <li>2</li>
  <li>3</li>
  <li>4</li>
  <li>5</li>
  <li>6</li>
</ul>

http://jsfiddle.net/8jqbjese/2/

Flexbox 挑战与限制

挑战在于将一组弹性项目居中并将它们左对齐。但是除非每行有固定数量的盒子,并且每个盒子都是固定宽度的,否则目前使用 flexbox 是不可能的。

使用问题中发布的代码,我们可以创建一个新的 flex 容器来包装当前的 flex 容器 (ul),这样我们就可以将 ul 与 [=15] 居中=].

然后 ul 的弹性项目可以与 justify-content: flex-start 左对齐。

#container {
    display: flex;
    justify-content: center;
}

ul {
    display: flex;
    justify-content: flex-start;
}

这将创建一组居中的左对齐弹性项目。

此方法的问题在于,在某些屏幕尺寸下,ul 的右侧会出现间隙,使其不再居中显示。

发生这种情况是因为在 flex 布局中(实际上,通常 CSS)容器:

  1. 不知道元素何时换行;
  2. 不知道之前占用的space现在是空的,并且
  3. 不会重新计算其宽度以收缩包裹较窄的布局。

右边白色的最大长度space是容器期望在那里的弹性项目的长度。

在下面的演示中,通过水平调整window的大小,可以看到白色space来来去去。

DEMO


更实用的方法

使用 inline-blockmedia queries.

可以在没有 flexbox 的情况下实现所需的布局

HTML

<ul>
    <li>1</li>
    <li>2</li>
    <li>3</li>
    <li>4</li>
    <li>5</li>
    <li>6</li>
</ul>

CSS

ul {
    margin: 0 auto;                  /* center container */
    width: 1200px;
    padding-left: 0;                 /* remove list padding */
    font-size: 0;                    /* remove inline-block white space;
                                        see  */
}

li {
    display: inline-block;
    font-size: 18px;                 /* restore font size removed in container */
    list-style-type: none;
    width: 150px;
    height: 50px;
    line-height: 50px;
    margin: 15px 25px;
    box-sizing: border-box;
    text-align: center;
}

@media screen and (max-width: 430px) { ul { width: 200px; } }
@media screen and (min-width: 431px) and (max-width: 630px) { ul { width: 400px; } }
@media screen and (min-width: 631px) and (max-width: 830px) { ul { width:600px;  } }
@media screen and (min-width: 831px) and (max-width: 1030px) { ul { width: 800px; } }
@media screen and (min-width: 1031px) and (max-width: 1230px) { ul { width: 1000px; } }

上面的代码呈现了一个水平居中的容器,其中的子元素左对齐,如下所示:

DEMO


其他选项

  • Desandro Masonry

    Masonry is a JavaScript grid layout library. It works by placing elements in optimal position based on available vertical space, sort of like a mason fitting stones in a wall. You’ve probably seen it in use all over the Internet.

    source: http://masonry.desandro.com/

  • CSS Grid Layout Module Level 1

    This CSS module defines a two-dimensional grid-based layout system, optimized for user interface design. In the grid layout model, the children of a grid container can be positioned into arbitrary slots in a predefined flexible or fixed-size layout grid.

    source: https://drafts.csswg.org/css-grid/

正如@michael 所建议的,这是当前 flexbox 的一个限制。但是,如果您仍想使用 flexjustify-content: center;,那么我们可以通过添加虚拟 li 元素并分配 margin-left.

来解决此问题
    const handleResize = () => {
        const item_box = document.getElementById('parentId')
        const list_length  = item_box.clientWidth
        const product_card_length = 200 // length of your child element
        const item_in_a_row = Math.round(list_length/product_card_length)
        const to_be_added = item_in_a_row - parseInt(listObject.length % item_in_a_row) // listObject is the total number items
        const left_to_set = (to_be_added - 1 ) * product_card_length // -1 : dummy item has width set, so exclude it when calculating the left margin 
        const dummy_product = document.querySelectorAll('.product-card.dummy')[0]
        dummy_product.style.marginLeft = `${left_to_set}px`
    }
    handleResize() // Call it first time component mount
    window.addEventListener("resize", handleResize); 

勾选这个fiddle (resize and see ) or video for reference

获得所需边距样式的一种方法是执行以下操作:

#container {
    display: flex;
    justify-content: center;
}

#innercontainer {
    display: flex;
    flex: 0.9; -> add desired % of margin
    justify-content: flex-start;
}

你可以用CSS网格实现,就用repeat(autofit, minmax(width-of-the-element, max-content))

ul {
       display: grid;
       grid-template-columns: repeat(auto-fit, minmax(210px, max-content));
       grid-gap: 16px;
       justify-content: center;
       padding: initial;
}

li {
    list-style-type: none;
    border: 1px solid gray;
    padding: 5px;
    width: 210px;
}
<ul>
    <li>1</li>
    <li>2</li>
    <li>3</li>
    <li>4</li>
    <li>5</li>
    <li>6</li>
    <li>7</li>
</ul>

http://jsfiddle.net/rwa20jkh/

我 运行 在使用 React Native 编码时遇到了这个问题。使用 FlexBox 可以得到一个优雅的解决方案。在我的特殊情况下,我试图使用 alignItems 将三个弹性框 (Flex: 2) 居中放置在另一个内部。我想出的解决方案是使用两个空的 s,每个都有 Flex: 1.

<View style={{alignItems: 'center', flexWrap: 'wrap', flexDirection: 'row'}}>
  <View style={{flex: 1}} />
    // Content here
  <View style={{flex: 1}} />
</View>

很容易转换为网络/CSS。

您可以放置​​与其他 class 相同的不可见元素(出于展示目的在示例中删除)并将高度设置为 0。这样,您将能够从一开始就证明这些项目是合理的网格。

例子

<div class="table-container">
  <div class="table-content">
    <p class="table-title">Table 1</p>
    <p class="mesa-price">$ 20</p>
  </div>
  
  <!-- Make stuff justified start -->
  <div class="table-content" style="opacity: 0; cursor: default; height: 0; margin-bottom: 0;"></div>
  <div class="table-content" style="opacity: 0; cursor: default; height: 0; margin-bottom: 0;"></div>
  <div class="table-content" style="opacity: 0; cursor: default; height: 0; margin-bottom: 0;"></div>
  <div class="table-content" style="opacity: 0; cursor: default; height: 0; margin-bottom: 0;"></div>
</div>

结果

我发现解决此问题的最简单方法就是简单地添加一些具有可见性的占位符:隐藏。这样它在环绕时保持正确的间距。

不知何故,@Joe82 的回答对我不起作用。但是,我发现这是正确的方法。在阅读了关于 auto-fitauto-fillthis 文章后,我发现自动调整会尽可能创建新列;但是,它会折叠它们,以便网格项目填满整个可用空间 space,如果它们的最大宽度允许的话。

对于那些感兴趣的人: auto-fill 也会在可能的情况下创建新的列,但不会让它们折叠,因此它会创建空的可见列,这些列将占用 space。 您可以在下图中看到这一点:

因此,我使用 repeat(auto-fit, minmax(10rem, 1fr) 作为 `grid-template-columns。

然后我将 justify-items 设置为 center,这会将其网格区域内的项目对齐到内联轴上。

我还希望列和行之间有一些“边距”,所以我添加了 row-gap1remcolumn-gap 以及 shorthand。

因此,我将以下 CSS 添加到我的 div 中,其中包含网格项目:

.card-section {
  width: 100%;
  display: grid;
  justify-items: center;
  gap: 1rem;
  grid-template-columns: repeat(auto-fit, minmax(10rem, 1fr));
}

我知道这并不是 OP 想要实现的目标,但也许它可以帮助那些和我有同样问题并且偶然发现这个问题的人。